将子矢量合并/展平为单个矢量c ++(将2d转换为1d)

时间:2013-06-25 10:14:10

标签: c++ vector stl

我有vector<vector<int> > Y。我想将Y中的子向量(称为y)合并为一个vector<int>。但我不想对它们进行排序,即按照它们出现的顺序合并它们。我怎么能有效地做到这一点,也许是通过使用STL算法? std::merge方法通过排序合并我不想要的。

编辑: 我想要的是:给定{{1,6,5},{5,3-1,77},{0},...}返回{1,6,5,5,3,-1,77, 0,...}

2 个答案:

答案 0 :(得分:14)

这个词是连接拼合

std::vector<int> a { 1,2,3 },
                 b {9,0,-7};

std::vector<int> c(begin(a), end(a));
c.insert(end(c), begin(b), end(b));

或者,更简单:

auto c = a;
c.insert(end(c), begin(b), end(b));

c现在包含1,2,3,9,0,-7

您可以将其概括为处理嵌套容器的情况:

template <template<typename...> class R=std::vector, 
          typename Top, 
          typename Sub = typename Top::value_type> 
   R<typename Sub::value_type> flatten(Top const& all)
{
    using std::begin;
    using std::end;

    R<typename Sub::value_type> accum;

    for(auto& sub : all)
        accum.insert(end(accum), begin(sub), end(sub));

    return accum;
}

如果您想将元素从第一个容器移动到最后一个容器(如果元素只能移动,或者复制起来很昂贵),请使用std::move std::back_inserter或将std::make_move_operator应用于 auto x = to_vector(std::vector<int> { 1,2,3 }, std::list<int> { 9,8,11 }, std::set<int> { 42 }); 每个源迭代器。

Coliru

上查看

更新:Variadic连接

最初,我原本以为你会追求一种可变的解决方案:让我演示一下如何使这更加通用,所以你可以说:

// fun with maps:
auto y = concatenate<std::map<long, std::string> >(
        std::map<int,      const char*> { { 1, "one" }, { 2, "two" } },
        std::map<unsigned, std::string> { { 1, "one" }, { 3, "three" } }            
    );

事实上,我把它变得如此通用,你将异构集合连接成“任意”容器:

to_vector

您(正确地)期望concatenate<std::vector<...>>只是#include <vector> #include <utility> #include <iterator> namespace detail { template <typename R> void do_concatenation(R& accum) {} template <typename R, typename First, typename... More> void do_concatenation(R& accum, First const& first, More const&... more) { using std::begin; using std::end; std::copy(begin(first), end(first), std::inserter(accum, end(accum))); do_concatenation(accum, more...); } } template <typename Result, typename... Containers> Result concatenate(Containers const&... containers) { Result accum; detail::do_concatenation(accum, containers...); return accum; } template <typename First, typename... More> std::vector<typename First::value_type> to_vector(First const& first, More const&... containers) { return concatenate<std::vector<typename First::value_type>>(first, containers...); } /// demo #include <set> #include <list> #include <iostream> #include <map> #include <string> int main() { auto x = to_vector(std::vector<int> { 1,2,3 }, std::list<int> { 9,8,11 }, std::set<int> { 42 }); for (auto i : x) std::cout << i << " "; std::cout << std::endl; // fun with maps: auto y = concatenate<std::map<long, std::string> >( std::map<int, const char*> { { 1, "one" }, { 2, "two" } }, std::map<unsigned, std::string> { { 1, "one" }, { 3, "three" } } ); for (auto kvp : y) std::cout << "(" << kvp.first << ", " << kvp.second << ")"; } 的便利缩写。这是完整的monty,看到住在Coliruideone

1 2 3 9 8 11 42 
(1, one)(2, two)(3, three)

输出:

{{1}}

答案 1 :(得分:10)

template <typename T>
std::vector<T> flatten(const std::vector<std::vector<T>>& v) {
    std::size_t total_size = 0;
    for (const auto& sub : v)
        total_size += sub.size(); // I wish there was a transform_accumulate
    std::vector<T> result;
    result.reserve(total_size);
    for (const auto& sub : v)
        result.insert(result.end(), sub.begin(), sub.end());
    return result;
}

与@ not-sehe的解决方案相比,这具有一些性能优势:

  • 计算结果的最终大小并预先分配存储空间。这意味着无需重复重新分配。
  • 它使用范围插入而不是单元素插入,就像其他版本一样。这允许容器应用一些优化,特别是如果元素可以轻易地复制(即每个内部容器有一个memcpy)。

缺点是,它只适用于vector,而不是deque或list。