【问题标题】:Create vector of sizes of the vectors inside a "2d-vector" (vector< vector<> >)?在“2d-vector”(vector<vector<> >)内创建向量大小的向量?
【发布时间】:2011-10-24 19:27:37
【问题描述】:

我有一个向量的向量,比如说

std::vector< std::vector<int> > my2dArray;

现在我想要一个包含my2dArray 内向量大小的向量。手动这看起来像

std::vector<int> mySizes;
for (int i = 0; i < my2dArray.size(); i++ )
{
  mySizes.push_back( my2dArray[i].size() );
}

有没有更“优雅”的方式来做到这一点 - 无需手动编写循环 - 通过使用一些 STL 算法等?

【问题讨论】:

  • 人们对循环有什么看法?我是说真的,我看看发布的替代方案,我宁愿写 for 循环。
  • 这写起来可能很烦人,但我认为,它比你在这里得到的答案更具可读性......也许只是用 for_each 和 lambda 重写它......(编辑:约翰写了几乎一样……下次要先刷新)
  • @john 循环没有问题。在这种情况下,我主要对替代方案感到好奇。我将在这里坚持循环,因为它优于其他建议的解决方案(在 C++03 中),见下文。
  • 有效地使用 STL 算法等只需要一点时间来适应 - 我发现到处都明确地写出代码会分散我的实际意图。
  • @john:人们反对编写循环的原因是什么?好吧,你可以写错循环,例如。很难写错std::transform 而不出现编译错误。使用算法指定意图(std::transform 是一个转换的循环),而要知道循环在做什么,您必须查看它在做什么。算法唯一真正的缺点是必须编写函子等冗长,在 C++11 中,使用 lambdas 可以缓解这种情况。

标签: c++ stl vector


【解决方案1】:

C++03:

typedef std::vector<int> IntVec;
std::vector<size_t> sizes(my2dArray.size());
std::transform(my2dArray.begin(), my2dArray.end(), sizes.begin(), 
               std::mem_fun_ref(&IntVec::size));

【讨论】:

  • 如果算法能够与整个容器一起工作,那就太好了,比如sizes = std::transform(my2dArray, std::mem_fun_ref(&amp;IntVec::size));。 (那么如果我们也可以删除那个丑陋的 mem_fun_ref,结果会和脚本语言一样好。)
  • 是的,这行得通,谢谢。然而,在我的测试中,它比基于循环的解决方案慢了大约 15% 到 20%。所以我想,我会坚持循环..
  • @imre:你总是可以拥有更符合你想要做的事情的包装器。
  • @Georg Fritzsche:是的,我知道,我只是希望它们是标准库的一部分。这些是可以吓跑 C++ 初学者的东西。 “你可以自己动手”与“你必须自己动手”完全不同。无论如何,这有点离题了。
【解决方案2】:

关于您将获得的最佳效果(需要 C++11)

std::vector<int> mySizes(my2dArray.size());
auto getSize = [](const std::vector<int> & v) { return v.size(); };
std::transform(my2dArray.begin(), my2dArray.end(), mySizes.begin(), getSize);

这并不是一个巨大的改进,如果你不能使用 lambda,我认为额外的麻烦是不值得的。

【讨论】:

  • 抱歉,我目前没有可用的 C++11,所以很遗憾我无法测试您的解决方案。
  • 好吧,看起来我确实使用适当的标志在 gcc 4.4 中已经提供了自动功能。我会试一试(不过还不能真正使用这些功能)。
  • 不,我又错了。看起来 lambdas 还没有在 gcc 中,甚至没有使用 c++0x 标志..
  • @janitor:它们从 4.5 开始可用
【解决方案3】:

这行得通。我试图让 sizeVec 作为 Sizes 的成员,但这并没有像this 问题中讨论的那样起作用。

#include <string>
#include <iostream> 
#include <algorithm>
#include <vector>

class Sizes
{
public:
    Sizes( std::vector<int>& v ) : sizeVec( v ) {}
    void operator() ( std::vector<int>& v ) { 
        sizeVec.push_back( v.size() );  
    }
    std::vector<int>& sizeVec;
};

void outFunc (int i) {
    std::cout << " " << i;
}
int _tmain(int argc, _TCHAR* argv[])
{
    std::vector<std::vector<int>> twodVec;

    std::vector<int> vec;
    vec.push_back( 6 );
    twodVec.push_back( vec );
    vec.push_back( 3 );
    twodVec.push_back( vec );
    vec.push_back( 8 );
    twodVec.push_back( vec );
    vec.push_back( 3 );
    twodVec.push_back( vec );

    std::vector<int> sizeVec;
    Sizes sizes(sizeVec);
    std::for_each( twodVec.begin(), twodVec.end(), sizes );
    std::for_each( sizeVec.begin(), sizeVec.end(), outFunc );

    return 0;
}

编辑:Oli Charlesworth 已经回答了我提出的问题;您可以将对象更改为:

class Sizes
{
public:
    void operator() ( std::vector<int>& v ) { 
        sizeVec.push_back( v.size() );  
    }
    std::vector<int> sizeVec;
};

然后在 main:

Sizes sizes;
sizes = std::for_each( twodVec.begin(), twodVec.end(), sizes );
std::for_each( sizes.sizeVec.begin(), sizes.sizeVec.end(), outFunc );

如果您愿意。如果你有提升,你就可以使用Boost.Ref 来做更简单的事情。

编辑 2: 更改函子以通过引用接收向量,而不是 Alf P Steinbach 在我提出的问题中建议的值。

【讨论】:

  • 非常感谢您的建议!它有效,但不幸的是,这种解决方案比其他提议的方法慢得多。我猜这主要是由于与push_back() 相关的可能的内存重新分配。您第一次编辑的修改版本表现更差,可能是由于额外的复制操作 (?)。
  • 如果内存分配是问题,您可以创建具有正确大小的向量,如其他两个答案中所做的那样
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-10-23
  • 1970-01-01
  • 2018-10-23
  • 1970-01-01
  • 2020-01-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多