簡體   English   中英

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

[英]How do I iterate over a vector and also know the index of the element?

我需要訪問向量中的每個元素,還需要知道元素所在的索引。

到目前為止,我可以想出兩種方法

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

留下類型簽名。 看起來我也不能使用自動

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

哪個更有效或者有更好的方法來做到這一點?

對於向量或其他隨機訪問容器,它幾乎沒有區別。 我可能會選擇第二個,因為它更容易閱讀,而且可能稍微快一點,因為只有一個循環變量要更新。 另一種選擇是:

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

對於非隨機訪問的容器, []不可用,並且std::distance效率低下; 在這種情況下,如果您需要索引,第一種方法會更好(盡管您需要修復它,以便它不會嘗試在 for-initialiser 中聲明兩個不同類型的變量)。

答案就在問題中—— “知道元素在哪個索引中。” .

所以 -

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

在性能方面它們是相同的(但您始終可以對自己進行配置)。

其他方式。

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

這是使用zip_iterator庫中的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 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';
}

您可以使用 Boost.Range 的indexed適配器,它使用返回當前索引 (duh) 的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";

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

有點懸而未決,由於逗號運算符的工作方式,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
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM