【问题标题】:Conditionally use a varied number of items in each iteration在每次迭代中有条件地使用不同数量的项目
【发布时间】:2012-11-13 12:13:01
【问题描述】:

我想这真的很简单,只是涉及使用迭代器和 .MoveNext() 方法。

但是假设您正在遍历一个集合,您在集合上做了一些工作,但根据每个“循环”中的某些条件,您可能需要抓取 2 个或更多项目并基本上跳过它们,这样您就不会循环接下来通过它们。

例子:

foreach (Fish fish in ParcelOfFish)
{
    GiverPersonFish(fish);
}

在这里,我只是遍历 Fish 的集合并将它们传递给一个方法。有些鱼很小,所以我必须再给那个人一条,这样它就不会饿死了。

foreach (Fish fish in ParcelOfFish)
{
    GiverPersonFish(fish);

    if (fish.IsSmall)
    {
        GiverPersonFish(ParcelOfFish.MoveNext()); // here I want to give him the next fish
    }
}

这将如何工作,以便我给出的第二条鱼不会在下一个循环中迭代?

另外,为了让这件事变得更棘手,一个人可能得到一条大鱼和一条小鱼是不公平的,所以每当有一条小鱼时,我都不想从迭代中抓起另一条小鱼然后继续。

所以如果订单是

Small
Big
Big
Small
Big
Small

在第一次“循环”之后,他会得到两个小的(索引 0 和 3),它会像这样遍历其余部分:

Big
Big
Big
Small

编译器似乎不喜欢在迭代时这样修改迭代。

【问题讨论】:

  • 按原样,你似乎把所有的鱼都给了同一个人,那么每次迭代高级多条鱼是怎么回事?
  • foreach 不适合这里。也许使用队列更好。
  • @Y.Ecarri 好吧,我们真的不知道 GivePersonFish() 方法中发生了什么,这并不重要。
  • @Y.Ecarri 所以你说这个人只会吃一天,我宁愿 TeachPersonToFish() 他会吃一辈子?
  • @IngóVals 不,我对道德原则没有意见,我只是基于面向对象的设计标准。如果某些信息在 for-each 循环的范围内不相关,那么它不会关心循环迭代。您对鱼在人群中的分布方式表示关注,因此鱼和人都是相关的,或者两者都与迭代无关。如果您需要对鱼进行最佳分布,请尝试不同的方法,例如 Sum-Bottleneck 算法或任何其他分区算法。

标签: c# iterator iteration


【解决方案1】:

从设计上讲,迭代并不意味着像这样工作。如果您需要更灵活的行为,您应该使用 for 循环。

【讨论】:

    【解决方案2】:

    其实可以通过Enumerator解决

    using (var enumerator = ParcelOfFish.GetEnumerator())
    {
        // Bla bla whatever you need, but remember the first call to .MoveNext();
        if (!enumerator.MoveNext())
                break;
    
        // Your actions here. MoveNext() is bool and proceeds to the new item.
        // Try using while (!condition) { } here.
    }
    

    【讨论】:

      【解决方案3】:

      不要使用 foreach 循环 (foreach(Foo foo in bar)),而是使用普通的旧 for 循环 (for(int i = 0; i < bar.Length; i++))。

      这会让你做这样的事情:

      for (int i = 0; i < ParcelOfFish.Length; i++)
      {
          Fish fish = ParcelOfFish[i];
          GiverPersonFish(fish);
      
          if (fish.IsSmall && i+1 < ParcelOfFish.Length)
          {
              GiverPersonFish(ParcelOfFish[++i]); // give him the next fish
          }
      }
      

      使用 for 循环还可以让您在列表中查找另一条小鱼,将其交给此人,然后将其从列表中删除(这次假设 ParcelOfFish 是列表,而不是数组):

      for (int i = 0; i < ParcelOfFish.Count; i++)
      {
          Fish fish = ParcelOfFish[i];
          GiverPersonFish(fish);
      
          if (fish.IsSmall)
          {
              for (int j = i+1; j < ParcelOfFish.Count; j++)
              {
                  Fish fish2 = ParcelOfFish[j];
                  if (fish2.IsSmall)
                  {
                      GiverPersonFish(fish2); // give him the next small fish
                      ParcelOfFish.RemoveAt(j);
                      break;                    
              }
          }
      }
      

      【讨论】:

      • 这也不会给下一条小鱼
      • 我回答了问题的第一部分,并指出了如何解决问题的其余部分,但我也为第二部分添加了一个示例。
      【解决方案4】:

      我会改用队列。

      var queue = new Queue<Fish>(ParcelOfFish);
      while (queue.Count > 0)
      {
          var fish = queue.Dequeue();
      
          if (fish.IsSmall && queue.Count > 0) 
          {
              var fish2 = queue.Dequeue();
      
              if (fish2.IsSmall)
                  GiverPersonFish(fish); // give them the first small fish
              else
                  queue.Enqueue(fish); // throw it back to the end of the queue
      
              GiverPersonFish(fish2);
          }
          else
              GiverPersonFish(fish);
      }
      

      也适用于堆栈。

      【讨论】:

      • queue.Count &gt; 0queue.Any() 更好,因为这是枚举集合的扩展。
      • @AgentFire 是真的!已编辑。
      【解决方案5】:

      试试

      Enumerator<Fish> enumerator = ParcelOfFish.GetEnumerator();
      Queue<Fish> bigFishCache = new Queue<Fish>(){ };
      Boolean smallFishSwitch = false;
      
      while(enumerator.MoveNext())
      {
          if(smallFishSwitch)
          {
              if(enumerator.Current == BigFish)
              {
                   bigFishCache.Enqueue(enumerator.Current);
              }
              else
              {
                   smallFishSwitch = false;
                   GivePersonFish(enumerator.Current);
                   ForEach(Fish fish in bigFishCache)
                   {
                        GivePersonFish(fish);
                   }
                   bigFishCache.Clear();
              }
          }
          else
          {
              smallFishSwitch = enumerator.Current == SmallFish;
              GivePersonFish(enumerator.Current);
          }    
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-02-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-28
        • 2019-07-03
        相关资源
        最近更新 更多