如何使用 range-v3 压缩向量的向量
How to zip vector of vector with range-v3
(这是 的后续)
如果我有两个(或更多)向量,我可以 zip
它们与 range-v3
像这样:
std::vector< int > v1{1,1,1};
std::vector< int > v2{2,2,2};
auto v = ranges::views::zip( v1, v2 )
| ranges::views::transform( ... );
这很好用,但在实践中,我没有明确的向量,但我有一个向量的向量。我想执行以下操作,但是 it doesn't give the same result。 (其实我也不确定结果是什么,也不知道怎么判断结果是什么!)
std::vector< std::vector< int > > V{{1,1,1},{2,2,2}};
auto vV = ranges::views::zip( V )
| ranges::views::transform( ... );
我怎样才能像压缩一些显式向量那样压缩 vector< vector >
? 我试过使用 join
和 stride
, chunk
, 等但是还没找到神奇的组合.
ranges::views::zip( V )
仅压缩一个向量,而不压缩其内容。 (类似于 std::make_tuple(v)
做 std::tuple<vector<int>>
)。
问题是 vector 具有运行时大小,因此从其内容构造一个 tuple
需要一些帮助:
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);
}
然后:
std::vector< std::vector< int > > V{{1,1,1},{2,2,2}};
auto vV = zip_vector<2>( V )
| ranges::views::transform( ... );
我想如果您在编译时不知道外部 vector
的大小,唯一合理的解决方案就是解决它。与其尝试 zip
,我建议在此基础上使用 accumulate
,因为在这种情况下它看起来更通用。
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());
}
)
编辑:
我忘了必须复制范围。
根据您链接到的问题,我认为这个特定问题是一个 XY 问题,即没有理由涉及 zip
来解决这个问题,除了建立在以前的解决方案之上。当范围数量在编译时已知时,zip
可能是一种合理的方法,但当范围数量仅在 运行 时已知时,它只会妨碍。
假设你有一个 vector<vector<int>>
,与上一个问题类似,所有内部向量的大小都相同,下面是我在 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);
});
这里是 demo。
压缩 vector<vector<T>>
是您想要做的事情,因为它允许您转置这些范围。
其他答案足以解释为什么你不能 zip
vector<vector<T>>
。
但是,您可以像 Eric Niebler 在演示 range-v3 的演讲中所做的那样编写一个显式转置适配器
- https://www.youtube.com/watch?v=mFUXNMfaciE
- https://github.com/ericniebler/range-v3/blob/master/example/calendar.cpp
但是,这是一个昂贵的适配器,昂贵的适配器会被忽略 https://github.com/ericniebler/range-v3/issues/776
(这是
如果我有两个(或更多)向量,我可以 zip
它们与 range-v3
像这样:
std::vector< int > v1{1,1,1};
std::vector< int > v2{2,2,2};
auto v = ranges::views::zip( v1, v2 )
| ranges::views::transform( ... );
这很好用,但在实践中,我没有明确的向量,但我有一个向量的向量。我想执行以下操作,但是 it doesn't give the same result。 (其实我也不确定结果是什么,也不知道怎么判断结果是什么!)
std::vector< std::vector< int > > V{{1,1,1},{2,2,2}};
auto vV = ranges::views::zip( V )
| ranges::views::transform( ... );
我怎样才能像压缩一些显式向量那样压缩 vector< vector >
? 我试过使用 join
和 stride
, chunk
, 等但是还没找到神奇的组合.
ranges::views::zip( V )
仅压缩一个向量,而不压缩其内容。 (类似于 std::make_tuple(v)
做 std::tuple<vector<int>>
)。
问题是 vector 具有运行时大小,因此从其内容构造一个 tuple
需要一些帮助:
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);
}
然后:
std::vector< std::vector< int > > V{{1,1,1},{2,2,2}};
auto vV = zip_vector<2>( V )
| ranges::views::transform( ... );
我想如果您在编译时不知道外部 vector
的大小,唯一合理的解决方案就是解决它。与其尝试 zip
,我建议在此基础上使用 accumulate
,因为在这种情况下它看起来更通用。
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());
}
)
编辑: 我忘了必须复制范围。
根据您链接到的问题,我认为这个特定问题是一个 XY 问题,即没有理由涉及 zip
来解决这个问题,除了建立在以前的解决方案之上。当范围数量在编译时已知时,zip
可能是一种合理的方法,但当范围数量仅在 运行 时已知时,它只会妨碍。
假设你有一个 vector<vector<int>>
,与上一个问题类似,所有内部向量的大小都相同,下面是我在 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);
});
这里是 demo。
压缩 vector<vector<T>>
是您想要做的事情,因为它允许您转置这些范围。
其他答案足以解释为什么你不能 zip
vector<vector<T>>
。
但是,您可以像 Eric Niebler 在演示 range-v3 的演讲中所做的那样编写一个显式转置适配器
- https://www.youtube.com/watch?v=mFUXNMfaciE
- https://github.com/ericniebler/range-v3/blob/master/example/calendar.cpp
但是,这是一个昂贵的适配器,昂贵的适配器会被忽略 https://github.com/ericniebler/range-v3/issues/776