Can this double loop be rewritten using ranges views split() ?
#include <vector>
#include <span>
struct MyPair
{
int a;
char b;
};
vector<MyPair> path = {{1,'a'},{1,'z'},{2,'b'},{2,'y'}};
vector<span<MyPair> > spans;
for (int i=0; i < path.size();)
{
auto r = path | ranges::views::drop(i) | views::take_while([&](const MyPair& p){return p.a == path[i].a;});
int size = ranges::distance(r);
span<Range> ranges(&path[i], size);
spans.push_back(ranges);
i = size ;
}
I want a view of views looking like
{{{1,'a'},{1,'z'}},{{2,'b'},{2,'y'}}}
CodePudding user response:
Can this double loop be rewritten using ranges views split() ?
Since you're not using a range as a delimiter to split the original range, instead you're using a predicate to split the range, views::split
doesn't actually solve the problem.
However, C 23 adopted views::chunk_by
, and according to its description in [range.chunk.by.overview]:
chunk_by_view
takes aview
and a predicate, and splits the view intosubrange
s between each pair of adjacent elements for which the predicate returnsfalse
.
The for-loop can be rewritten using views::chunk_by
with the appropriate predicate:
vector<MyPair> path = ...
auto spans = path | std::views::chunk_by([](const auto& l, const auto& r) {
return l.a == r.a;
});
But currently, no compiler implements this range adaptors, the alternative is to use range-v3's views::group_by
.
CodePudding user response:
In the absence of views::chunk_by, here is my code, using a good old for loop:
#include <vector>
#include <span>
struct MyPair
{
int a;
char b;
};
vector<MyPair> path = {{1,'a'},{1,'z'},{2,'b'},{2,'y'}};
vector<span<MyPair> > spans;
int i_prev=0;
for (int i=0;i < path.size(); i )
{
if (path[i].a != path[i_prev].a)
{
spans.push_back(span<MyPair>(&path[i_prev], i - i_prev));
i_prev=i ;
}
}
spans.push_back(span<MyPair>(&path[i_prev], path.size() - i_prev));