如何使用 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 > 我试过使用 joinstride, 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://github.com/ericniebler/range-v3/issues/776