How to zip vector of vector with range-v3

橙三吉。 提交于 2020-05-29 08:44:09

问题


(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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!