问题
(This is a follow-on to Sum vector with range-v3)
If I have two (or more) vectors, I can zip
them together with range-v3
like this:
std::vector< int > v1{1,1,1};
std::vector< int > v2{2,2,2};
auto v = ranges::views::zip( v1, v2 )
| ranges::views::transform( ... );
This works well, but in practice, I don't have explicit vectors, but I do have a vector of vectors. I'd like to do the following, but it doesn't give the same result. (In fact, I'm not sure what the result is, and I don't know how to determine what the result is!)
std::vector< std::vector< int > > V{{1,1,1},{2,2,2}};
auto vV = ranges::views::zip( V )
| ranges::views::transform( ... );
What can I do to zip a vector< vector >
like I did to zip a few explicit vectors? I've tried using join
along with stride
, chunk
, etc. but haven't found the magic combination.
回答1:
I suppose if you don't know the size of external vector
in compile time the only reasonable solution that remains is work around it. Instead of trying to zip
it I would suggest going with accumulate
on top of that as it seems more versatile in this situation.
std::vector< std::vector< int > > V{{1,1,1},{2,2,2}};
auto vV = ranges::accumulate(
V,
std::vector<ResultType>(V[0].size()),
[](const auto& acc, const auto& next) {
auto range = ranges::views::zip(acc, next) | ranges::views::transform(...);
return std::vector<int>(range.begin(), range.end());
}
)
EDIT: I forgot the range has to be copied.
回答2:
ranges::views::zip( V )
zips only one vector, not its content. (similarly to std::make_tuple(v)
which does std::tuple<vector<int>>
).
Issue is that vector has runtime size, so construct a tuple
like from its contents requires some help:
template <std::size_t ...Is, typename T>
auto zip_vector(std::index_sequence<Is...>, std::vector<std::vector<T>>& v)
{
assert(N <= v.size());
return ranges::views::zip(v[Is]...);
}
template <std::size_t N, typename T>
auto zip_vector(std::vector<std::vector<T>>& v)
{
return zip_vector(std::make_index_sequence<N>(), v);
}
And then:
std::vector< std::vector< int > > V{{1,1,1},{2,2,2}};
auto vV = zip_vector<2>( V )
| ranges::views::transform( ... );
回答3:
Based on the question you linked to, I think this particular question is an XY problem, i.e. there is no reason to involve zip
to solve this problem, other than building upon the previous solution. While zip
might have been a reasonable approach when the number of ranges was known at compile time, it just gets in the way when the number is only known at run-time.
So given that you have a vector<vector<int>>
, where similar to the previous question, all the internal vectors are the same size, here's how I would write it in range-v3:
namespace rv = ranges::views;
std::vector<std::vector<int>> v{{1,2,3},{4,5,6}};
int n = v.size();
int k = v[0].size();
auto vs = v | rv::join;
auto s = rv::iota(0, n + 1)
| rv::transform([=](int i){
return ranges::accumulate(
vs | rv::drop(i) | rv::stride(k), 0);
});
Here's a demo.
来源:https://stackoverflow.com/questions/61819277/how-to-zip-vector-of-vector-with-range-v3