如何遍历向量并知道元素的索引?

Posted

技术标签:

【中文标题】如何遍历向量并知道元素的索引?【英文标题】:How do I iterate over a vector and also know the index of the element? 【发布时间】:2012-09-11 19:14:16 【问题描述】:

我需要访问向量中的每个元素,并且还需要知道该元素所在的索引。

到目前为止,我可以想出两种方法

 for (iterator it= aVector.begin(), int index= 0; it!= aVector.end(); ++it, ++index)

留下类型签名。而且好像我不能使用自动

 for (int index = 0; index < aVector.size(); ++index)

    // access using []

哪个更有效或有更好的方法来做到这一点?

【问题讨论】:

如果您出于某种内在的基本原因需要索引,请使用第二个版本。 是的,如果您需要索引,请选择后者。 “哪一个效率更高?” 为什么不直接把它放在一个循环中并测量时间呢?就个人喜好而言,我会选择第二个……总是。看看第一个有多丑。 @BoBTFish:这不是“作弊”,也不是利用它是一个数组的事实;它使用迭代器是随机访问的事实,正如标准所说的那样。 第一个不会编译,所以我说第二个。 【参考方案1】:

对于向量或其他随机访问容器,它几乎没有什么区别。我可能会选择第二个,因为它更容易阅读,并且可能稍微快一些,因为只有一个循环变量需要更新。另一种选择是:

for (auto it = aVector.begin(); it != aVector.end(); ++it) 
    int index = std::distance(aVector.begin(), it);

对于非随机访问容器,[] 不可用,std::distance 效率低下;在这种情况下,如果您需要索引,第一种方法会更好(尽管您需要修复它,以便它不会尝试在 for-initialiser 中声明两个不同类型的变量)。

【讨论】:

这就是我的意思:p 这应该被修复以反映std::distance 返回std::iterator_traits&lt;InputIt&gt;::difference_type 的事实,这将是比int 更宽的类型。 (事实上​​很少有人会拥有足够大的容器来溢出int 这不是借口。)使用auto 的另一个原因 - 奇怪的是你为it 做的而不是index。跨度> 【参考方案2】:

答案就在问题中——“知道元素所在的索引。”

所以——

for (int index = 0; index < aVector.size(); ++index)

    // access using []

在性能方面它们是相同的(但您始终可以自我介绍)。

【讨论】:

索引应该是size_t 而不是int @Rémi 迂腐,应该是 vector::size_type :) @Rémi 是否有理由使用 size_t 而不是 int? 是的。在大多数现代编译器中,int 是 32 位,而 size_t 是 64 位。所以如果你有一个非常大的向量,使用 int 是行不通的。【参考方案3】:

另一种方式。

int count = 0;
for (auto& it : aVector) 
   count++;

【讨论】:

首先我想,“肯定有八个答案,已经有人提到了,毕竟这是最简单直接的方法。”没有。 +1 给你。【参考方案4】:

您可以使用 Boost.Range 的 indexed 适配器,它使用返回当前索引的 index 方法扩展范围的迭代器(废话)。

#include <boost/range/adaptor/indexed.hpp>

// ...
auto&& r = vec | boost::adaptors::indexed(0);
for(auto it(begin(r)), ite(end(r)); it != ite; ++it)
  std::cout << it.index() << ": " << *it << "\n";

遗憾的是,由于index 是迭代器方法的一部分,这意味着您不能使用新的基于范围的 for 循环,甚至不能使用仅提供元素访问权限的 BOOST_FOREACH。这是一个价值可疑的相当样板式的解决方法:

// note: likely contains typos or bugs
#include <boost/range/adaptors.hpp>

template<class IndexIt>
auto pair_index_value(IndexIt it)
    -> std::pair<std::size_t, decltype(*it)>

  return std::pair<std::size_t, decltype(*it)>(it.index(), *it);


// ...
using namespace boost::adaptors;

auto&& ir = vec | indexed; // because screw you Boost.Range
for(auto&& elem : boost::counting_range(ir.begin(), ir.end()) | transformed(pair_index_value))
  std::cout << elem.first << ": " << elem.second << "\n";

【讨论】:

【参考方案5】:

这是使用来自Boost.Iterator library 的zip_iteratorcounting_iterator 的解决方案。对于您的用例来说,这可能是方式过大,但它具有使用任何范围(不仅是向量)的优点,并且可以很好地适应标准算法的基于迭代器的设计,所以我发布它在这里:

#include <boost/iterator/counting_iterator.hpp>
#include <boost/iterator/zip_iterator.hpp>

#include <algorithm>
#include <iostream>
#include <list>

int main()

    typedef std::list<int> container;

    typedef boost::tuple<
        container::iterator,
        boost::counting_iterator<container::size_type>
    > tuple_type;

    typedef boost::zip_iterator<tuple_type> it_type;

    container l1, 2, 3, 4;

    it_type begin(tuple_type(l.begin(), 0));
    it_type const end(tuple_type(l.end(), l.size()));

    // sample use with for loop
    for (it_type it = begin; it != end ; ++it)
    
        int value = it->get<0>();
        int index = it->get<1>();
        // do whatever you want with value and index
    

    // sample use with standard algorithm
    auto res = std::find_if(begin, end,
        [](boost::tuple<int, int> const & t)
         return t.get<0>() > 2; ); // find first element greater than 2

    std::cout << "Value: " << res->get<0>() << '\n' <<
                 "Index: " << res->get<1>() << '\n';

【讨论】:

【参考方案6】:

c++11:

for (auto i=aVector.begin(); i!=aVector.end(); ++i) 
    cout << "I am at position: " << i-aVector.begin() << endl;
    cout << "contents here is: " << *i << endl;

c++ 老派:

for (vector<int>::const_iterator i=aVector.begin(); i!=aVector.end(); ++i) 
    cout << "I am at position: " << i-aVector.begin() << endl;
    cout << "contents here is: " << *i << endl;

【讨论】:

在第一个中,i 是向量的元素,而不是索引或迭代器。您无法从范围样式的 for 循环中获取索引。 (如果是向量,你可以用&amp;i-&amp;vector[0] 破解它,但如果容器类型发生变化,它会无声无息地破坏,所以不要这样做)。 @MikeSeymour 我认为你的hack只有在for循环使用for (auto&amp; i : aVector)时才有效(?),否则,就像现在写的那样,i是元素的副本向量。 @BrianNeal:原来如此。这是不这样做的另一个原因。 已更新为可用的。很遗憾,在这种情况下,自动功能不起作用。那会很酷。 @matiu 不要把坏掉的留在那里,把它删掉并显示更好的版本。【参考方案7】:
for (iterator it = aVector.begin(), int index= 0; it!= aVector.end(); ++it, ++index)

这不会编译。但这并不重要,因为只要我们谈论的是std::vector,那么通过索引访问就是一个简单的指针算术和解引用——所以实际上与迭代器一样快。所以你的版本 2 没问题。

不过,我会进一步优化(如果您真的关心速度):

for (int index = 0, size = aVector.size(); index < size; ++index)

    // access using []

【讨论】:

为什么第一个编译不了?你输入了正确的迭代器类型吗? @kunj2aan:因为你不能在一个声明中声明不相关类型的变量(iteratorint)。 @kunj2aan 你为什么不直接try it。注意solution is simple。【参考方案8】:

有点悬念,由于逗号运算符的工作方式,OP 的第一条语句无法编译。我确定 OP 只是使用 iterator 的简写而不是完整的类型名,但这不是问题:

for (iterator it= aVector.begin(), int index= 0; it!= aVector.end(); ++it, ++index)

逗号运算符要么分隔两个表达式(并返回第二个表达式的结果),要么用于分隔声明中的变量。 for 参数的第一个参数将采用任何一种形式,因此混淆了它们是不同语法的事实。

#include <vector>
#include <iostream>

int main()

    std::vector<int> aVector = 1,1,2,3,5,8,13;

    // option 1. Both loop variables declared outside the for statement, initialized inside the for statement
    int index1 = 0;
    decltype(aVector.begin()) it1;
    for (it1 = aVector.begin(), index1=0; it1!= aVector.end(); ++it1, ++index1)
    
        std::cout << "[" << index1 << "]=" << *it1 << std::endl;
    

    // option 2. The index variable declared and initialized outside, the iterator declared and initialized inside
    int index2=0;
    for (auto it2 = aVector.begin(); it2!= aVector.end(); ++it2, ++index2)
    
        std::cout << "[" << index2 << "]=" << *it2 << std::endl;
    

#if 0
    // option3 (the OP's version) won't compile. The comma operator doesn't allow two declarations.
    for (auto it3 = aVector.begin(), int index3=0 ; it3!= aVector.end(); ++it3, ++index3)
    
        std::cout << "[" << index3 << "]=" << *it3 << std::endl;
    
#endif

【讨论】:

好吧,Fiktik observed this back in 2012。 我展示了两个选项以接近他的示例的 OP 预期语法,并扩展了 Fiktik 的答案。

以上是关于如何遍历向量并知道元素的索引?的主要内容,如果未能解决你的问题,请参考以下文章

如何从传递给某些 STL 算法的谓词中获取元素的索引?

如何使用二分搜索将元素插入已排序的向量中

是否有多种方法可以 cin 向量元素?

迭代数组并在索引处插入元素

如何在向量的给定索引范围内找到最小元素?

如何在 AVX 向量中找到元素的索引?