【问题标题】:Iterating over a vector in reverse direction反向迭代向量
【发布时间】:2010-11-17 15:06:14
【问题描述】:

我需要遍历从结尾到开头的向量。 “正确”的方式是

for(std::vector<SomeT>::reverse_iterator rit = v.rbegin(); rit != v.rend(); ++rit)
{
    //do Something
}

当doSomething涉及知道实际索引时,则需要用rit做一些计算才能得到它,比如index = v.size() - 1 - (rit - v.rbegin)

如果无论如何都需要索引,那么我坚信使用该索引进行迭代会更好

for(int i = v.size() - 1; i >= 0; --i)
{
    //do something with v[i] and i; 
}

这会发出警告,i 已签名,v.size() 未签名。 改为

for(unsigned i = v.size() - 1; i &gt;= 0; --i) 只是功能错误,因为这本质上是一个无限循环:)

什么是做我想做的事的美学好方法

  • 没有警告
  • 不涉及演员表
  • 不过分冗长

我希望我不是在寻找不存在的东西:)

【问题讨论】:

  • 循环条件 i != std::numeric_limits&lt;unsigned&gt;::max() ... 如果您认为它很冗长,请使用 UINT_MAX。
  • 到目前为止,我认为做演员看起来是最干净的解决方案:-)
  • 只需在 i 上设置一个上限,即 v.size()。
  • @Downvoter:您能解释一下否决票吗?这是一个精确的问题,感谢@Nim,我终于得到了答案。
  • for (size_t i = v.size(); i --&gt; 0; )

标签: c++ stl iteration


【解决方案1】:

正如您所指出的,i &gt;= 0 无符号条件的问题在于条件始终为真。不要在初始化 i 时减去 1,然后在每次迭代后再次减去 1,而是在检查循环条件后减去 1:

for (unsigned i = v.size(); i-- > 0; )

我喜欢这种风格有几个原因:

  • 虽然i 将在循环结束时回绕到UINT_MAX,但它并不依赖这种行为——如果类型已签名,它的工作方式相同。依赖未签名的环绕式对我来说有点像 hack。
  • 它只调用一次size()
  • 它不使用&gt;=。每当我在 for 循环中看到该运算符时,我都必须重新阅读它以确保没有错误。
  • 如果更改条件中的间距,可以使其使用"goes to" operator

【讨论】:

  • 不应该是 size_t 而不是 unsigned 吗?
  • 如果您真的预计拥有比unsigned、@Yes123 更多的项目,那可能会更好,但正式正确的类型应该是std::vector&lt;SomeT&gt;::size_type,或者,现在,只是auto .
【解决方案2】:

没有什么可以阻止您的 reverse_iterator 循环也使用多个其他答案中描述的索引。这样您就可以在 // do the work 部分中根据需要使用迭代器或索引,而额外花费最少。

size_t index = v.size() - 1;
for(std::vector<SomeT>::reverse_iterator rit = v.rbegin(); 
    rit != v.rend(); ++rit, --index)
{
  // do the work
}

虽然我很想知道您需要索引做什么。访问v[index] 与访问*rit 相同。

【讨论】:

  • 这实际上是任何非随机访问的底层类型的唯一正确答案。假设 std::vector&lt;SomeT&gt; 在某个地方被 typedef 了,我宁愿使用正确的迭代器,以防我后来决定使用列表、多重集、映射等。
  • 使用 auto 减少冗长。
【解决方案3】:

要美观! ;)

for(unsigned i = v.size() - 1; v.size() > i; --i)

【讨论】:

  • @Armen,嗯,但无符号(默认为 int)可能小于 vectorsize_type,至于为什么您可以拥有超过 40 亿个条目在你的向量中,这是一个不同的问题...... :).. 好吧,好吧......我放弃......
  • 如果 v.size() == UINT_MAX 呢?我知道这在实践中从未发生过,但这是一个理论上的缺陷
  • @JB: vector::size_type is not unsigned int 也是一个理论上的缺陷。但老实说,只要真的没有实际机会会适得其反,我就不在乎理论上的缺陷——Armen Tsirunyan 7 秒前编辑
  • 我不知道是不是我没有有效地使用环绕,但我通常使用for (i = v.size(); i &gt; 0; --i) 来做,然后使用i-1 作为实际索引。我猜是偏好问题。
【解决方案4】:

我更喜欢反向迭代器变体,因为它仍然很容易解释并且可以避免与索引相关的错误。

有时您可以简单地使用BOOST_REVERSE_FOREACH,这将使您的代码如下所示:

reverse_foreach (int value, vector) {
   do_something_with_the_value;
}

实际上,对于这类循环,您始终可以使用foreach 语句,但是它们变得有点不明显:

size_t i = 0;

foreach (int value, vector) {
   do_something;
   ++i;
}

【讨论】:

    【解决方案5】:

    尝试做一会儿:

    std::vector<Type> v;
    // Some code 
    if(v.size() > 0)
    {
        unsigned int i = v.size() - 1;
        do
        {
            // Your stuff
        }
        while(i-- > 0);
    }
    

    【讨论】:

    • 好的,没问题;)。我测试了do while并且它有效。我并不是说这是最好的解决方案,但它是可用的。
    【解决方案6】:

    您好,我认为更好的方法是使用迭代器,就像您在第一个示例中使用的那样,如果您需要获取迭代器索引,您可以使用 std::distance 来计算它,如果我理解你的问题

    【讨论】:

      【解决方案7】:

      循环条件i != std::numeric_limits&lt;unsigned&gt;::max() ...如果您认为它很冗长,请使用UINT_MAX。 或其他方式:
      for(unsigned j=0, end=v.size(), i=end-1; j&lt;end; --i, ++j)

      for(unsigned end=v.size(), i=end-1; (end-i)&lt;end; --i)

      【讨论】:

        【解决方案8】:

        我认为:

        for(unsigned i = v.size() - 1; i >= 0; --i)
        

        如果你检查就好了

        !v.empty()
        

        早些时候。

        【讨论】:

        • @HardCoder1986:再想想 :)
        【解决方案9】:
        for (it = v.end()-1; it != v.begin()-1; --it)
        {
        }
        

        "goes to" operator 绝对让我头疼。

        【讨论】:

        • @Floella AFAIK,这不起作用(迭代器不支持减去整数)。要反向迭代,我认为你必须使用std::vector&lt;T&gt;::reverse_iterator a la stackoverflow.com/a/4206142/5835083,如果你真的坚持使用减法,则使用std::distance
        猜你喜欢
        • 1970-01-01
        • 2020-11-06
        • 2014-09-15
        • 1970-01-01
        • 2010-10-27
        • 2017-08-29
        • 1970-01-01
        • 2014-09-19
        • 1970-01-01
        相关资源
        最近更新 更多