【问题标题】:How to concatenate many std::vectors?如何连接许多 std::vectors?
【发布时间】:2015-04-17 04:35:00
【问题描述】:

已经有一个关于如何连接两个向量的问题:Concatenating two std::vectors。但是,我发现开始一个新的比较合适,因为我的问题更具体一点......

我有两个如下所示的类:

class AClass {
public:
    std::vector<double> getCoeffs() {return coeffs;}
private:
    std::vector<double> coeffs;
};

class BClass {
public:
    std::vector<double> getCoeffs() {return ...;}
private:
    std::vector<AClass> aVector;
};

连接 aVector 中每个元素的系数的最佳方法是什么(即避免不必要的复制等)?

我的第一次尝试是

std::vector<double> BClass::getCoeffs(){
    std::vector<double> coeffs;
    std::vector<double> fcoefs;
    for (int i=0;i<aVector.size();i++){
        fcoefs = aVector[i].getCoeffs();
        for (int j=0;j<fcoefs.size();j++{
            coeffs.push_back(fcoefs[j]);
        }        
    }
    return coeffs;
}

我已经知道如何避免内部 for 循环(感谢上面提到的帖子),但我很确定,在一些标准算法的帮助下,这可以在一行中完成。

目前我无法使用 C++11。尽管如此,我也会对如何在 C++11 中做到这一点感兴趣(如果比“没有 C++11”有任何优势的话)。

编辑:我将尝试重新表述这个问题,以使其更清楚。 连接两个向量可以通过插入来完成。对于我的例子,我会使用这个:

std::vector<double> BClass::getCoeffs(){
    std::vector<double> coeffs;
    std::vector<double> fcoefs;
    for (int i=0;i<aVector.size();i++){
        fcoefs = aVector[i].getCoeffs();
        coeffs.insert(coeffs.end(),fcoefs.begin(),fcoefs.end());        
    }
    return coeffs;
}

是否可以避免 for 循环? 我可以想象可以写出类似的东西

for_each(aVector.begin(),aVector.end(),coeffs.insert(coeffs.end(),....);

【问题讨论】:

  • 看到这个answer by Ben Voigt
  • @MohitBhasi 这是我提到的另一个问题的副本。也许我应该将标题更改为“如何连接许多 std::vectors”;)
  • 总结大小,预留,循环使用范围插入。您无能为力。
  • AClass 是否有意返回系数的副本而不是 const 引用,或者这仅仅是由于示例的最小化?

标签: c++ vector stdvector


【解决方案1】:

你可以在 C++11 中做到这一点:

std::for_each(aVector.begin(), aVector.end(), [&](AClass i){const auto& temp = i.getCoeffs(); coeffs.insert(coeffs.end(), temp.begin(), temp.end());});

C++03 更难,因为它缺少 lambdas 和 bind

你能做的最好的就是在你的内部循环中使用复制:

for(std::vector<AClass>::iterator it = aVector.begin(); it != aVector.end(); ++it){
     const std::vector<double>& temp = it->getCoeffs();
     coeffs.insert(coeffs.end(), temp.begin(), temp.end());
}

它们本质上是相同的,尽管您可以通过从 getCoeffs 返回一个 const std::vector&lt;double&gt;&amp; 来改善两者的运行时间。

编辑:

Arg,刚刚看到您在问题中添加了insert。我以为我真的会在那里帮助你。作为一个安慰提示,您在这里真正要问的是使std::vectorstd::vectors 变平。那有一个答案here。但是,如果您可以访问 boost,您应该查看:http://www.boost.org/doc/libs/1_57_0/libs/multi_array/doc/reference.html#synopsis

【讨论】:

    【解决方案2】:

    第一步是避免额外的分配。如果你知道你不会增加返回值,你可以保留到正好合适的大小。

    std::vector<double> BClass::getCoeffs(){
      typedef std::vector<double> dvec;
      dvec coeffs;
      typedef std::vector<AClass> avec;
      typedef std::vector<dvec> ddvec;
      ddvec swap_space;
      swap_space.reserve(aVector.size());
      size_t capacity = 0;
      for (avec::const_iterator it = aVector.begin(); it != aVector.end(); ++it) {
        dvec v = it->getCoeffs(); // RVO elision!
        capacity += v.size();
        swap_space.push_back();
        v.swap(swap_space.back());
      }
      dvec retval;
      retval.reserve(capacity);
      for (ddvec::iterator it = swap_space.begin(); it != swap_space.end(); ++it) {
        retval.insert( retval.end(), it->begin(), it->end() );
      }
      return retval; // NRVO
    }
    

    这应该避免每个 AClass 分配一次以上(由他们的 API 强制!您应该有一个 vector&lt;?&gt; const&amp; 访问器),加上一个返回值分配。

    建议修复AClass

    【讨论】:

    • 对不起,但没有进一步的解释,我不明白为什么它必须如此复杂。顺便说一句,'AClass::coeffs' 都是固定大小的。想改用 std::array 但我不能使用 C++11。
    • @tobi303 好吧,每个 get 分配一个缓冲区。所以如果我调用它两次,我分配两次。但是我还想在开始追加之前调整组合缓冲区的大小,因此我需要在汇总每个子缓冲区的长度时存储它们,然后将它们追加到目标中。更简单的解决方案——获取、追加、重复而不是获取重复追加重复——执行 O(lg(n)) 更多分配(n 是元素总数)。以上内容可能不值得,但它确实告诉我你的界面,复制缓冲区,应该改进如果这是一个性能瓶颈。
    • 非常感谢。我将不得不更深入地了解正在发生的事情以及对我的应用程序来说最佳解决方案是什么。
    猜你喜欢
    • 2010-09-17
    • 1970-01-01
    • 2021-02-02
    • 1970-01-01
    • 2013-01-22
    • 2017-10-15
    相关资源
    最近更新 更多