如何迭代向量并知道元素的索引?

时间:2012-09-19 13:07:44

标签: c++ algorithm vector stl iteration

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

到目前为止,我可以提出两种方式

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

留下类型签名。它看起来我不能使用自动

 for (int index = 0; index < aVector.size(); ++index)
{
    // access using []
}

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

8 个答案:

答案 0 :(得分:15)

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

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

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

答案 1 :(得分:7)

答案在于问题 - “知道元素所在的索引。”

所以 -

for (int index = 0; index < aVector.size(); ++index)
{
    // access using []
}

表现方面他们是一样的(但你总是可以自己描绘一下)。

答案 2 :(得分:3)

以下是使用Boost.Iterator library中的zip_iteratorcounting_iterator的解决方案。对于您的用例,它可能 way 过度杀伤,但它具有使用任何范围(不仅仅是向量)并且与基于迭代器的标准算法设计很好地契合的优点,所以我发布了它在这里:

#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 l{1, 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';
}

答案 3 :(得分:3)

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

#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";

答案 4 :(得分:3)

另一种方式。

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

答案 5 :(得分:1)

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;
}

答案 6 :(得分:0)

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 []
}

答案 7 :(得分:0)

有点悬而未决,由于逗号运算符的工作方式,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
}