将向量的向量合并为单个向量
Posted
技术标签:
【中文标题】将向量的向量合并为单个向量【英文标题】:Merge vector of vectors into a single vector 【发布时间】:2016-05-19 04:25:12 【问题描述】:我有 T 的向量向量:
std::vector<std::vector<T>> vector_of_vectors_of_T;
我想将它们全部合并到 T 的单个向量中:
std::vector<T> vector_of_T;
我目前正在使用这种方法:
size_t total_size 0 ;
for (auto const& items: vector_of_vectors_of_T)
total_size += items.size();
vector_of_T.reserve(total_size);
for (auto const& items: vector_of_vectors_of_T)
vector_of_T.insert(end(vector_of_T), begin(items), end(items));
还有更直接的方法吗?像一个准备好的标准功能?如果没有,是否有更有效的手动方式?
【问题讨论】:
我认为这个问题更适合codereview.stackexchange.com @Luca Pizzamiglio 感谢您的纠正vector_of_vectors_of_T.SelectMany(...
-- 哦等等,语言错误:P
@Humam 如果您想获得太多 STL,您可以将其用于 reserve
部分:vector_of_T.reserve(std::accumulate(std::begin(vector_of_vectors_of_T), std::end(vector_of_vectors_of_T), 0, [](size_t size, std::vector<T> const& vec) return size + vec.size(); ));
这里没有太大的改进空间,除了使用移动迭代器(如果你不再需要原来的)。这是 range-v3 中的 action::join
,因此您可能会在标准中看到它……有一天。
【参考方案1】:
尝试编写一个通用的join
是一个很好的练习。下面的代码采用嵌套容器R1<R2<T>
并返回一个连接容器R1<T>
。请注意,由于标准库中的分配器参数,这有点麻烦。没有尝试检查分配器的兼容性等。
幸运的是,Eric Niebler 即将推出的 range-v3 库中有 action::join
函数,该函数已经非常强大,并且现在可以在 Clang 上运行:
#include <range/v3/all.hpp>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <numeric>
#include <vector>
// quick prototype
template<template<class, class...> class R1, template<class, class...> class R2, class T, class... A1, class... A2>
auto join(R1<R2<T, A2...>, A1...> const& outer)
R1<T, A2...> joined;
joined.reserve(std::accumulate(outer.begin(), outer.end(), std::size_t, [](auto size, auto const& inner)
return size + inner.size();
));
for (auto const& inner : outer)
joined.insert(joined.end(), inner.begin(), inner.end());
return joined;
int main()
std::vector<std::vector<int>> v = 1, 2 , 3, 4 ;
// quick prototype
std::vector<int> w = join(v);
std::copy(w.begin(), w.end(), std::ostream_iterator<int>(std::cout, ",")); std::cout << "\n";
// Eric Niebler's range-v3
std::vector<int> u = ranges::action::join(v);
std::copy(u.begin(), u.end(), std::ostream_iterator<int>(std::cout, ",")); std::cout << "\n";
Live Example
【讨论】:
顺便说一句,这种“可连接容器”的数学术语是monad。 (这个概念比你可以用迭代器编写的任何东西都更笼统。)【参考方案2】:使用back_inserter
和move
;
size_t total_size 0 ;
for (auto const& items: vector_of_vectors_of_T)
total_size += items.size();
vector_of_T.reserve(total_size);
for (auto& items: vector_of_vectors_of_T)
std::move(items.begin(), items.end(), std::back_inserter(vector_of_T));
而不是copying
,std::move
给了它一点性能增强。
【讨论】:
没有基准测试,从抽象的角度来看,它应该比我的更快吗?之前也需要预留吗? 这可能比带有移动迭代器的范围插入版本效率低,特别是对于可复制的元素类型(范围插入可能会进行大量优化)。【参考方案3】:我想您可以尝试在循环中使用std::merge
/std::move
- 这已经是现有的标准算法。不知道是不是更快。
【讨论】:
以上是关于将向量的向量合并为单个向量的主要内容,如果未能解决你的问题,请参考以下文章