【问题标题】:Need to iterate over entire object except for first two elements. Is there a design pattern?需要遍历整个对象,除了前两个元素。有设计模式吗?
【发布时间】:2020-10-12 09:37:59
【问题描述】:

我有一个std::vector,我想遍历除前两个之外的每个对象。如果我不想要两个 foreach 循环将是完美的。即for(const auto i : items)

我想到的可能的解决方案是删除前两个并在最后重新添加

const auto firstEle = myVec[0];
const auto secEle = myVec[1];
myVec.erase(myVec.begin());
myVec.erase(myVec.begin());
for(const auto i : items)
{
  //do stuff with i
}
myVec.insert(myVec.begin(), secEle);
myVec.insert(myVec.begin(), firstEle);

或者有某种标志

unsigned int i = 0;
for(const auto j : items)
{
  if(i < 2)
  {
    i++;
    continue;
   }
   //do stuff with j
}

或者使用while循环

unsigned int i = 2;
while(i < myVec.size())
{
  const auto j = myVec[i];
  //do stuff with j

  i++;
}

所有这些似乎都比它们需要的复杂。有没有更好更简单的解决方案?

【问题讨论】:

    标签: c++ loops design-patterns foreach


    【解决方案1】:

    我通常使用常规循环来处理这些事情:

    // verify myVec.size() > 2
    for(auto it = myVec.begin()+2; it != myVec.end(); ++it) {
        // work
    }
    

    如果你想要 C++11 lambda 魔法,那么

    std::for_each(v.begin()+2, v.end(), [](auto& element) {
         // do stuff
    });
    

    会做的。

    【讨论】:

    • 或者,您可以使用 std::advance 跳过前 2 个元素,但无论您是否这样做,我仍然会推荐此答案中的方法,而不是问题中的方法。
    • it 不是一个迭代器,所以还需要取消引用吗?如果是这样,它比我的 3 建议更好吗? :)
    • 这似乎可行,但有 UB 风险:如果 myVec.size() == 1myVec.begin()+2 将使迭代器增加超过 myVec.end(),并且可能会出现粉红色的大象。即使迭代器只是指针,这也会发生,因为it 永远不会与myVec.end() 相等(因为它会从一开始就更大)。
    • @cmaster-reinstatemonica 我猜你没有仔细阅读第一条评论。
    • @northerner 我不明白你的评论。这里没有“更好”,您要求通用做法。这些是我经常看到的做法。你的也很好。
    【解决方案2】:

    在 C++20 中,您可以使用std::views::drop。直接取自cppreference.com的示例:

    #include <ranges>
    #include <vector>
    #include <iostream>
     
    int main()
    {
        std::vector<int> nums = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
        for (int i : nums | std::views::drop(2))
        {
            std::cout << i << ' ';
        }
        std::cout << '\n';
        return 0;
    }
    

    输出:

    3 4 5 6 7 8 9 
    

    【讨论】:

      【解决方案3】:

      解决此类问题的最简单方法是简单地退回到索引循环:

      for(int i = 2; i < myVec.size(); i++) {
          //do stuff with `myVec[i]`
      }
      

      对于std::vector&lt;&gt;,这与基于迭代器的循环一样有效,并且循环控制准确地说明了它在盖子上的作用。最重要的是,因为您正在比较 &lt; 的整数而不是 != 的迭代器,所以当向量太短时,您不会冒任何触发未定义行为的风险。

      【讨论】:

      • 我在一个循环中多次访问每个元素的内容。所以我会做const auto ele = myVec[i],对吧?除了效率之外,我发现没有[ ] 会更容易阅读。
      • @northerner 好吧,如果需要更改,我会使用引用而不是值,即 const auto&amp; element = ...auto&amp; element = ...。是的,这是避免[i] 重复的典型方法。不过,更易读的内容取决于具体情况。
      猜你喜欢
      • 2018-03-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-07
      • 1970-01-01
      • 2023-01-10
      • 2013-07-12
      • 1970-01-01
      相关资源
      最近更新 更多