在 C++ 中迭代不同大小的向量映射

Iterating map of vectors of different sizes in C++

提问人:huzzm 提问时间:12/18/2015 最后编辑:huzzm 更新时间:12/18/2015 访问量:1047

问:

所以我用 C++ 声明了以下映射:

typedef vector<Vector2D> stackPoints; 
typedef map<int, stackPoints> mapPoints; 
mapPoints drawingPoints;

给它加值后,我想输出其中的所有元素,但是不同关键位置的向量大小不一样:

我正在使用以下两个不起作用的 for 循环。有时程序在运行时崩溃,并给我超出范围的矢量错误。

for (int j = 0; j < drawingPoints.size(); j++)
{
    for (int i = 0; i < drawingPoints[j].size(); i++)
    {
        cout << "(...)" << endl
    }
}

在我看来,内部 for 循环经历了恒定的次数,就好像以下情况是不可能的:

1) 第一个向量的大小为 1,因此内部 for 循环将执行一次。

2) 然后地图的第二个向量的大小为 5,现在我希望 for 循环经过 5 次,但这似乎不起作用。

**编辑**

我使用整数键作为计数器,因此当我添加另一对时,我会将其递增 1。

C++ 字典 向量

评论

1赞 aschepler 12/18/2015
drawingPoints[j]获取带有 key 的条目,而不是 -th 条目!jj
0赞 huzzm 12/18/2015
是的,这就是我想要的,不是吗?取决于 drawingPoints[ j ] 处向量的大小 - 它会发生变化!- 我希望内部for循环的执行频率相同。
0赞 Fantastic Mr Fox 12/18/2015
对于您的编辑,如果 int 只是一个指示条目数的索引,为什么不只使用 .然后你就可以完全按照你所做的事情去做。std::vector<stackPoints>
0赞 huzzm 12/19/2015
是的,你完全正确,我的坏^^

答:

1赞 Sergey Kalinichenko 12/18/2015 #1

问题在于迭代地图:你可以这样做的事实完全是偶然的 - 你的地图键的类型恰好是 ,所以作为它的索引工作得很好。但是,并非所有 s 都会在映射中包含任何内容,因此代码不起作用。drawingPoints[j]intjj

以下是遍历地图的方式:

for(auto& kvp : drawingPoints) {
    cout << "Key " << kvp.first << " has the following values:" << endl;
    for (auto n : kvp.second) {
        cout << n << " ";
    }
    cout << endl;
}

上面的示例需要 C++11。如果您使用较旧的编译器,请使用此 Q&A 使用迭代器遍历映射。

评论

0赞 huzzm 12/18/2015
我使用整数键作为计数器,因此当我添加另一对时,我会将其递增 1。
0赞 Sergey Kalinichenko 12/18/2015
@huzzm确切地说,它添加了另一对,除非键恰好在那里,在这种情况下,你要遍历它对应的向量。
0赞 Sergey Kalinichenko 12/18/2015
@huzzm 是的,它会起作用。但是,如果按顺序迭代时键始终存在,则最好使用向量的向量,因为向量通常比映射更快,占用的内存更少。
2赞 R Sahu 12/18/2015 #2
for (int j = 0; j < drawingPoints.size(); j++)
{
    // This is wrong.
    // j is not necessarily a valid key in the map.
    for (int i = 0; i < drawingPoints[j].size(); i++)
    {
        cout << "(...)" << endl
    }
}

使用迭代器来避免此类问题。

mapPoints::iterator map_begin = drawingPoints.begin();
mapPoints::iterator map_end = drawingPoints.end();
for ( ; map_begin != map_end; ++map_iter )
{
   stackPoints::iterator v_iter = map_iter->second.begin();
   stackPoints::iterator v_end = map_iter->second.end();
   for ( ; v_iter != v_end; ++v_iter )
   {
      cout << "(...)" << endl
   }
}

如果您使用的是 C++11 编译器,则可以使用:

for ( auto& map_item : mapPoints )
{
   for ( auto& v_item : map_item.second )
   {
      cout << "(...)" << endl
   }
}
2赞 Fantastic Mr Fox 12/18/2015 #3

出于多种原因,您应该使用迭代器。

  1. 您的地图可能不包含从 0 到 的每个元素,对于它不包含的每个元素,当您遍历它时,您将创建它。drawingPoints.size()
  2. 您的最高条目可能更大,在这种情况下,您将永远无法达到它。drawingPoints.size()

让我们看一下最外层的循环,如果你想为它定义一个迭代器,你应该做以下事情:

for (mapPoints::Iterator it = drawingPoints.begin(); it != drawingPoints.end(); it++) {

这将创建一个迭代器,您可以查看该迭代器(通过执行 或 )。it->*it

更多信息可以在这里找到。

评论

0赞 Francis Cugler 12/18/2015
我正要添加一个答案,建议在使用地图时使用迭代器,但你打败了我!