如何连接多个std::vector?

4

已经有一个问题讨论了如何连接两个向量: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;
}

我已经知道如何避免内部循环(感谢上述帖子),但我相信通过一些std算法的帮助,这可以在一行中完成。
目前我无法使用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(),....);

这个有用吗:https://dev59.com/CXA75IYBdhLWcg3wqK50 - m0bi5
2
请查看Ben Voigt的这个答案:https://dev59.com/-mMm5IYBdhLWcg3wZ-XQ。 - user3920237
@MohitBhasi 那是我所提到的另一个问题的副本。也许我应该把标题改为“如何连接许多std ::向量”;) - 463035818_is_not_a_number
3
在循环中汇总大小、保留和使用范围插入。你能做的不多。 - T.C.
@MatthiasB 部分原因是由于示例的最小化,部分原因是有意为之,因为AClass和BClass都应该实现相同的接口,并且BClass不持有任何系数的私有副本(但是,我当然可以通过向BClass添加一个字段来改变它,该字段持有所有系数)。 - 463035818_is_not_a_number
显示剩余2条评论
2个回答

2
您可以在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更难,因为它没有lambda和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<double>&可以提高它们的运行效率。
编辑:哎呀,刚才看到你添加了“insert”到你的问题中。我还以为我能真正地帮助你呢。作为安慰,你真正问的是如何展开一个std::vector中的std::vectors。这个问题在这里有解答:https://dev59.com/vmw15IYBdhLWcg3wxunL。但如果你可以使用boost,你应该看一下:http://www.boost.org/doc/libs/1_57_0/libs/multi_array/doc/reference.html#synopsis

1
第一步是避免额外的分配。如果您知道不会增加返回值的大小,可以保留恰好正确的大小。
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<?> const&访问器),再加上一个用于返回值的分配。

建议修复AClass


抱歉,但是没有进一步的解释,我不明白为什么它必须如此复杂。顺便说一下,“AClass::coeffs”都是固定大小的。我想使用std::array,但我不能使用C++11。 - 463035818_is_not_a_number
@tobi303嗯,每个get都会分配一个缓冲区。所以如果我调用两次,就会分配两次。但是在开始添加之前,我还想确定组合缓冲区的大小,因此我需要存储每个子缓冲区,同时计算它们的长度,然后将它们附加到目标缓冲区中。更简单的解决方案--获取、附加、重复而不是获取重复附加重复--多做O(lg(n))次分配(n是元素的总数)。上述方法可能不值得,但这确实告诉我,如果您的接口复制缓冲区时是性能瓶颈,则应进行改进。 - Yakk - Adam Nevraumont
非常感谢。我需要深入研究才能真正理解发生了什么,以及对于我的应用程序来说最佳的解决方案是什么。 - 463035818_is_not_a_number

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接