在一系列范围内迭代 [英] Iterating over a range of ranges
问题描述
如果我有一个范围范围,是否有一种方法可以将它们连接在一起并迭加它们,就像它们是单个范围一样?
按范围指任何种类的容器或迭代器对。基本上与boost的范围。 Boost已经有一个函数用于连接两个范围与boost :: join,但是该函数不能加入任意数量的范围。
基本上,我看一个方法来做这个<$ p $ c>函数在这段代码中所做的:
std :: vector< std :: vector< int>> n = {{0,1},{2,3}};
for(auto i:many(n))
std :: cout<< i<< '\\\
';
这将输出0,1,2,3。
在C#中,我有 SelectMany
可以做到这一点。
这里是一个使用基于范围的平展迭代器的例子(取自此处并添加 boost :: make_iterator_range
以显示范围版本)(仍然需要工作):
#include< boost / iterator / iterator_adaptor.hpp>
#include< boost / range.hpp>
#include< iostream>
#include< vector>
#include< algorithm>
#include #include< string>
#include< utility>
template< typename Iter>
class flattening_iterator:
public boost :: iterator_adaptor<
flattening_iterator< Iter>,
Iter :: value_type :: iterator :: value_type,
boost :: forward_traversal_tag,
typename Iter :: value_type: :iterator :: value_type
>
{
private:
using super_t = boost :: iterator_adaptor<
flattening_iterator< Iter>,
Iter :: value_type :: iterator :: value_type,
boost :: forward_traversal_tag,
typename Iter :: value_type: :iterator :: value_type
> ;;
using inner_iterator = typename Iter :: value_type :: iterator;
public:
flattening_iterator(Iter it)
:super_t(it),
inner_begin(),
inner_end(),
outer_end b $ b {}
flattening_iterator(Iter begin,Iter end)
:super_t(begin),
inner_begin((* begin).begin()),
inner_end * begin_end(); $ begin $ end $ end $ end $ end $ end $ end $ end $ end。
private:
friend class boost :: iterator_core_access;
internal_iterator inner_begin;
inner_iterator inner_end;
Iter outer_end;
void increment()
{
if(this-> base_reference()== outer_end)
return; //在结束
++ inner_begin;
if(inner_begin == inner_end)
{
++ this-> base_reference();
inner_begin =(* this-> base_reference())。begin();
inner_end =(* this-> base_reference())。end();
}
}
value_type dereference()const
{
return * inner_begin;
}
};
模板< typename Iter>
auto flat_iter(Iter it) - > flattening_iterator<
{
return flattening_iterator< ITER>(it);
}
template< typename Iter>
auto flat_iter(Iter begin,Iter end) - > flattening_iterator<
{
return flattening_iterator< Iter>(begin,end);
}
template< typename Cont>
auto flatten(Cont& c) - > boost :: iterator_range< flattening_iterator< decltype(std :: declval< Cont>()。begin())>>
{
return boost :: make_iterator_range(flat_iter(c.begin(),c.end()),flat_iter(c.end()));
}
int main()
{
std :: vector< std :: vector< int> v1 {{1,2,3},{4,5,6},{7,8,9}};
for(auto i:flatten(v1))
{
std :: cout< i<< '';
}
}
输出 >
1 2 3 4 5 6 7 8 9
If I have a range of ranges, is there a way to join them together and iterate over them as if they were a single range?
By range, I mean any kind of container or iterator pair. Basically like boost's ranges. Boost already have a function for joining two ranges together with boost::join, but that function can't join an arbitary number of ranges.
Basically, I'm looking for a way to do what the the many
function does in this piece of code:
std::vector<std::vector<int>> n = {{0, 1}, {2, 3}};
for (auto i : many(n))
std::cout << i << '\n';
Which would output 0, 1, 2, 3.
In C#, I had SelectMany
which could do this.
Here is an example of a flattening iterator used with range-based for (taken from here and added boost::make_iterator_range
to show range version) (still needs work though):
#include <boost/iterator/iterator_adaptor.hpp>
#include <boost/range.hpp>
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <string>
#include <utility>
template <typename Iter>
class flattening_iterator :
public boost::iterator_adaptor<
flattening_iterator<Iter>,
Iter,
typename Iter::value_type::iterator::value_type,
boost::forward_traversal_tag,
typename Iter::value_type::iterator::value_type
>
{
private:
using super_t = boost::iterator_adaptor<
flattening_iterator<Iter>,
Iter,
typename Iter::value_type::iterator::value_type,
boost::forward_traversal_tag,
typename Iter::value_type::iterator::value_type
>;
using inner_iterator = typename Iter::value_type::iterator;
public:
flattening_iterator(Iter it)
: super_t(it),
inner_begin(),
inner_end(),
outer_end(it)
{}
flattening_iterator(Iter begin, Iter end)
: super_t(begin),
inner_begin((*begin).begin()),
inner_end((*begin).end()),
outer_end(end)
{}
using value_type = typename Iter::value_type::iterator::value_type;
private:
friend class boost::iterator_core_access;
inner_iterator inner_begin;
inner_iterator inner_end;
Iter outer_end;
void increment()
{
if (this->base_reference() == outer_end)
return; // At the end
++inner_begin;
if (inner_begin == inner_end)
{
++this->base_reference();
inner_begin = (*this->base_reference()).begin();
inner_end = (*this->base_reference()).end();
}
}
value_type dereference() const
{
return *inner_begin;
}
};
template <typename Iter>
auto flat_iter(Iter it) -> flattening_iterator<Iter>
{
return flattening_iterator<Iter>(it);
}
template <typename Iter>
auto flat_iter(Iter begin, Iter end) -> flattening_iterator<Iter>
{
return flattening_iterator<Iter>(begin, end);
}
template <typename Cont>
auto flatten(Cont& c) -> boost::iterator_range<flattening_iterator<decltype(std::declval<Cont>().begin())>>
{
return boost::make_iterator_range(flat_iter(c.begin(), c.end()), flat_iter(c.end()));
}
int main()
{
std::vector<std::vector<int>> v1{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
for (auto i : flatten(v1))
{
std::cout << i << ' ';
}
}
Output
1 2 3 4 5 6 7 8 9
这篇关于在一系列范围内迭代的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!