【问题标题】:Check if the element is the first or the last one in an std::vector检查元素是 std::vector 中的第一个还是最后一个
【发布时间】:2015-05-13 03:30:58
【问题描述】:

我有以下for each C++ 代码:

for (auto item : myVector)
{
    std::cout << item;

    if (item == orderBy.IsLast())       // <--- Check if this is the last element
        std::cout << "(Is last element) " << std::endl;
    else if (item == orderBy.IsFirst()) // <-- Check if this is the first element
        std::cout << "(Is first element)" << std::endl;
}

当然IfLast()IfFirst()std::vector 上不存在。是否有原生的std:: 方法来检查第一个和最后一个元素?

【问题讨论】:

  • 如果只是对头/尾元素的特殊操作,考虑把它带出循环。
  • 首选for(auto&amp; item: myVector)for(const auto&amp; item: myVector) 以防止复制和可变。
  • 另一个 C++11 之前的版本:stackoverflow.com/questions/151046/…

标签: c++ c++11 for-loop


【解决方案1】:

在这种情况下,您不应该使用基于范围的for,因为这种for“隐藏”了迭代器,并且您需要一个额外的计数器来跟踪向量中的位置。你可以简单地做

for(auto it = myVector.begin(); it != myVector.end(); ++it)
{
    if(it == myVector.begin()) // first element
    {
        // do something
    }
    else if(std::next(it) == myVector.end()) // last element
    {
        // do something else
    }
}

请注意,仅当您确定向量中没有重复项时,只需将 my.Vector.back() 与基于范围的元素进行比较即可。但如果例如最后一个元素的值在向量中出现多次,你只会找到它的第一个位置。所以这就是为什么如果没有额外的索引来跟踪你在向量中的确切位置,就没有使用基于范围的for 的好方法。

编辑另请参阅@thelink2012 的回答,了解如何“欺骗”基于范围的for,以便您可以隐式获取元素的位置。

【讨论】:

  • ,1 是多余的;甚至it + 1 都可以。
  • 无法理解为什么我不应该使用它。这是一个不好的做法吗?确实我不需要迭代器,但 item 元素...
  • 您可能还希望考虑一个向量,其第一个元素也是它的最后一个元素:-)
  • @Mendez 这不是一个坏习惯。取决于场景。如果要跟踪向量中的位置,最好使用迭代器进行循环。如果你只是想例如显示元素(而不是它们的位置),然后基于范围的 for 就可以了。
【解决方案2】:

使用std::vector::frontstd::vector::back 获取第一个和最后一个位置的数据的引用

Reference 在这里是一个关键字,因为您可以有效地检查您的迭代 item 的地址以及各个前/后引用的地址。在您的示例中,您将 item 按值而不是引用,因此这可能无法正常工作,请考虑使用此方法的示例:

for(auto& item : myVector) // take item by reference
{
    std::cout << item;
    if (&item == &myVector.back())
       std::cout << "(last element) " << std::endl;
    else if (&item == &myVector.front())
       std::cout << "(first element)" << std::endl;
}

如果对象重载了操作符&amp; 的地址(尽管这被认为是一种不好的做法)您可能想改用std::addressof

但是,此方法不适用于 std::vector&lt;bool&gt; 特化,因为它优化了向量以使用位有效地存储布尔值,并且由于我们不能引用位,因此从该数据结构中取出的所有引用都不完全是代理对象绑定到内部数据的地址。

【讨论】:

  • 我差点说你错了。但是在这里参考可以工作,+1。
  • 它将在std::vector&lt;bool&gt; :P 上中断(后者返回基于范围的代理,它们是右值,它不是真正的容器)但仍然很好。
  • @vsoftco 非常好的观点,可能很容易被忽视!我已经更新了答案。非常感谢您的提醒:)
  • @vsoftco:希望没有人使用这种异常。
  • @MatthieuM。你的意思是vector&lt;bool&gt; 还是答案?答案很好 IMO,不会发生任何错误(当然,除非您的矢量元素超载 operator&amp;)。甚至vector&lt;bool&gt;has its usage
【解决方案3】:

您可以再次搜索它,但这将是相当低效的。如果您需要有关当前项目位置的信息,您可能需要使用迭代器或索引:

for (std::size_t i=0; i<myVector.size(); ++i)
{
    auto& item = myVector[i];
    std::cout << item;

    if (i == (myVector.size() - 1))
       std::cout << "(Is last element) " << std::endl;
    else if (i == 0)
       std::cout << "(Is first element)" << std::endl;
}

【讨论】:

    【解决方案4】:

    使用std::vector::front() 作为第一个元素。
    最后一个元素使用std::vector::back()

    在调用这些函数之前,请确保 vector 不为空。

        if (!orderBy.empty() && item == orderBy.back()) <--- Check if this is the last element
    
        else if (!orderBy.empty() && item == orderBy.front()) <-- Check if this is the first element
    

    【讨论】:

    • 如果向量的最后一个元素重复了怎么办?这行不通,你必须跟踪索引。
    • @vsoftco,我不知道 OP 对这些检查的意图是什么。鉴于发布的代码,他们要么(1)不希望看到重复,要么(2)希望多次看到输出。
    【解决方案5】:

    对于基于值的比较,您可以使用myVector.front()/myVector[0] 作为第一个元素,myVector.back()/myVector[myVector.size()-1] 作为最后一个元素。

    建议
    默认情况下捕获引用以避免不需要的副本。例如

    for(const auto&amp; I : myVector)

    【讨论】:

      【解决方案6】:

      如果边界有特殊情况,则应使用 ol' 迭代器版本,但将第一个和最后一个情况与循环分开。

      如果case之后共享代码,你应该把它封装在一个函数中。

      我无法用手机编写代码:c

      【讨论】:

        【解决方案7】:

        这对我有用

        vector<int> vi {1,2,3,4};
        
        cout << "vi = {";
        for (const auto &e : vi) {
          cout << e;
        
          if (&e != &vi.back())
            cout << ',';
        }
        cout << '}' << endl;
        

        【讨论】:

        猜你喜欢
        • 2015-04-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-02-12
        相关资源
        最近更新 更多