【问题标题】:How to iterate through a vector of vector in C++?如何在 C++ 中遍历向量的向量?
【发布时间】:2021-08-26 04:51:20
【问题描述】:

我想知道是否可以通过迭代器访问std::vector<std::vector<int>> 的元素:我不明白为什么这不会编译:

#include<vector> 
#include<iostream> 

std::vector<std::vector<int>> vec {{1,2},{3,4}} ; 

// to access the single vector 
auto it = vec.begin() ; 

// to access the element of the vector 
auto iit = it.begin() ; 

这是我得到的错误:

prova.cpp: In function ‘int main()’:
prova.cpp:10:15: error: ‘class __gnu_cxx::__normal_iterator<std::vector<int>*, std::vector<std::vector<int> > >’ has no member named ‘begin’
   10 | auto iit = it.begin() ;

【问题讨论】:

  • 这段代码没有出现。你的意思是(*it).begin() 而不是it.begin()
  • 我建议使用ranged for loops 而不是显式使用迭代器。
  • auto iit = it-&gt;begin()auto iit = (*it).begin()(假设 it 不是结束迭代器)。请注意,iit 将仅引用其中一个包含向量的元素(例如 {1,2}{3,4},而不是两者)。
  • @Someprogrammerdude 为什么推荐使用 ranged base for 循环?
  • 从您接受的答案中可以看出,它们非常易于使用。 :)

标签: c++ matrix iterator std stdvector


【解决方案1】:

特别是随机访问迭代器中的迭代器模拟指针的行为。

例如,如果您有一个类的对象,例如:

struct A
{
    int x;
} a = { 10 };

和一个指向对象的指针:

A *pa = &a;

然后使用您需要编写的指针访问对象的数据成员,例如:

std::cout << pa->x << '\n';

或:

std::cout << ( *pa ).x << '\n';

所以考虑一下这个声明:

auto it = vec.begin();

作为指针的声明。

所以使用这个迭代器,您可以获得存储向量的迭代器,例如

auto iit1 = it->begin() ;  

auto iit2 = ( ++it )->begin();

使用这种方法,您可以编写嵌套的 for 循环来输出向量。

这是一个演示程序:

#include <iostream>
#include <vector>

int main() 
{
    std::vector<std::vector<int>> vec { { 1, 2 }, { 3, 4 } };
    
    for ( auto it = vec.cbegin(); it != vec.cend(); ++it )
    {
        for ( auto iit = it->cbegin(); iit != it->cend(); ++iit )
        {
            std::cout << *iit << ' ';
        }
        std::cout << '\n';
    }
    
    std::cout << '\n';
    
    return 0;
}

程序输出为:

1 2 
3 4

我使用了成员函数 cbegincend 而不是 beginend 来表明向量在循环中没有被更改。

要做到这一点,使用基于范围的 for 循环会更简单。例如:

#include <iostream>
#include <vector>

int main() 
{
    std::vector<std::vector<int>> vec { { 1, 2 }, { 3, 4 } };
    
    for (const auto &v : vec )
    {
        for ( const auto &item :v )
        {
            std::cout << item << ' ';
        }
        std::cout << '\n';
    }
    
    std::cout << '\n';
    
    return 0;
}

程序输出同上图。

在基于范围的 for 循环中,编译器本身会取消引用迭代器而不是您。

【讨论】:

    【解决方案2】:

    根据Cplusplus

    迭代器是指向某个范围内的某个元素的任何对象 元素(例如数组或容器)

    vector <int> v = {0,1,2};
    auto it = v.begin();
    // it is a iterator pointing to the first element of the vector
    // To access the first element, we will use *it
    
    cout << *it; // will output 0
    // Notice how * is used to get the value where it points at
    

    在您的情况下,vec 是向量的向量。 vec 的每个元素本身就是一个向量。上述代码 sn-p 中定义的v 的每个元素都是一个int

    std::vector<std::vector<int>> vec {{1,2},{3,4}} ; 
    
    // it is an iterator pointing to the elements of vec
    // Notice that it points to the elements of vec
    // Each element of vec is a vector itself
    // So it "points" to a vector
    auto it = vec.begin() ; 
    
    // to access the element of the vector 
    //auto iit = it.begin() ; 
    
    // To access the elements (which are int) of the vector, you need to use: 
    auto iit = (*it).begin();
    
    // *it is the value where it points to (which is basically the first vector )
    

    另一种迭代 vec 的方法是使用每个循环

    for(auto v : vec)
    {
         for(int a : v)
         {
             cout<<a;
             // a is an integer
         }
    }
    

    【讨论】:

      【解决方案3】:

      您可以从对内部向量的引用获得内部元素的迭代器。迭代器不是对元素的引用,但您必须取消引用它。改变这个:

      // to access the element of the vector 
      auto iit = it.begin() ; 
      

      auto iit = it->begin();
      

      不要使事情过于复杂。你像这样迭代一个向量:

      std::vector<T> vect;
      
      for (auto it = vect.begin(); it != vect.end(); ++it) {
           auto& element = *it;
           // element is a reference to the element in the vector
      }
      

      或使用基于范围的循环:

      for (auto& element : vect) {
           // element is a reference to the element in the vector
      }
      

      真的没有比这更复杂的了。

      当你有一个嵌套向量并且你想要迭代内部向量的元素时,你只需要首先获取外部向量的元素,然后是内部向量的元素:

      std::vector<std::vector<T>> vect2;
      for (auto& inner_vector : vect2) {
           // inner_vector is reference to element of vect2
           for (auto& element : inner_vector) {
                // element is reference to element of inner vector
           }
      }
      

      【讨论】:

        【解决方案4】:

        如果你真的想使用迭代器,下面的代码就可以了。

        #include<vector> 
        #include<iostream> 
        
        int main()
        {
            std::vector<std::vector<int>> vec {{1,2},{3,4}} ; 
            
            for (auto it = vec.cbegin(); it != vec.cend(); ++it)
            {
                for (auto iit = it->cbegin(); iit != it->cend(); ++iit)
                {
                    std::cout << "elem: " << *iit << "\n";
                }
            }
        }
        

        否则,请务必使用范围 for 循环。

        #include<vector> 
        #include<iostream> 
        
        int main()
        {
            std::vector<std::vector<int>> vec {{1,2},{3,4}} ; 
            for (const auto& inner_vec : vec)
            {
                for (const auto& elem : inner_vec)
                {
                    std::cout << "elem: " << elem << '\n';
                }
            }
            
        }
        

        【讨论】:

          【解决方案5】:
          auto iit = it.begin();
          

          无法编译,因为it 是一个迭代器,而不是一个向量。您应该使用重载的 value-of 运算符来获取 it 指向的向量。

          auto iit = (*it).begin();
          

          然后您可以正常使用迭代器。 您还可以使用基于范围的 for 循环:

          for(auto &row : vec) {
              for(auto &col : row) {
                  // do things
              }
          }
          

          【讨论】:

          • 通常最好使用基于范围的循环而不是迭代器?
          • @Andrea Range-based-for 只是语法糖。编译器将生成与使用迭代器时几乎相同的代码。我尽可能使用它们,因为它更易于书写和阅读。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-10-07
          • 2018-05-14
          • 2012-09-03
          • 1970-01-01
          • 2013-11-08
          相关资源
          最近更新 更多