【问题标题】:foreach with index [duplicate]带索引的 foreach [重复]
【发布时间】:2010-10-06 00:30:12
【问题描述】:

是否存在与 Python 的 enumerate() 和 Ruby 的 each_with_index 等效的 C#?

【问题讨论】:

  • 如果您使用的是 LINQ,则可以覆盖允许枚举的各种函数。否则,您通常会卡在使用自己递增的变量。
  • 我们可以将这个问题更新到现在有元组的 C# 7.0 吗?我想知道使用元组的解决方案会是什么样子。
  • 这难道不是foreach 的一个特性,您可以将每个元素与其在列表中的位置绝对解耦吗?

标签: c# foreach


【解决方案1】:

我为此保留了这个扩展方法:

public static void Each<T>(this IEnumerable<T> ie, Action<T, int> action)
{
    var i = 0;
    foreach (var e in ie) action(e, i++);
}

然后像这样使用它:

var strings = new List<string>();
strings.Each((str, n) =>
{
    // hooray
});

或者允许break-like 行为:

public static bool Each<T>(this IEnumerable<T> ie, Func<T, int, bool> action)
{
    int i = 0;
    foreach (T e in ie) if (!action(e, i++)) return false;
    return true;
}

var strings = new List<string>() { "a", "b", "c" };

bool iteratedAll = strings.Each ((str, n)) =>
{
    if (str == "b") return false;
    return true;
});

【讨论】:

  • 你不能打破这个 foreach 循环。
  • 那是因为它不是foreach循环。
  • @TriQ 这只是另一个喜欢它的原因,大多数时候。 :)
  • @DanFinch 我不是在刻薄,我在合理地寻找答案。
  • @TankorSmash 这是一种“扩展方法”。看看这个。一点很棒的 C# 魔法。
【解决方案2】:

您可以执行以下操作

foreach (var it in someCollection.Select((x, i) => new { Value = x, Index = i }) )
{
   if (it.Index > SomeNumber) //      
}

这将为集合中的每个条目创建一个匿名类型值。它将有两个属性

  • Value:与集合中的原始值
  • Index: 带有集合内的索引

【讨论】:

  • 聪明,但这就像用右手挠左耳一样。我想我会自己保留索引,所以我不会混淆未来的维护者。
  • @Neil,我很惊讶人们认为这是一个维护问题。 Select(和其他 LINQ 方法)的这种重载是为了完成这样的操作而提供的。
  • 我认为维护没有问题。如果未来的维护者无法访问 MSDN 文档并查找 Select 方法的重载,那是他们自己的问题。担心变量名?只需: (Value, Index) => 为 lambda 选择新的 { Value, Index }。
  • @Lodewijk 如果没有支持集合,IEnumerable&lt;T&gt;.ElementAt(i) 是 O(n)(请参阅 Schlemiel the Painter)。如果您有一个评估成本高且包含大量记录的惰性可枚举对象怎么办?使用 for 循环,您必须等待 IEnumerable&lt;T&gt;.Count() 返回才能开始处理记录。 for 循环通常不适用于IEnumerable&lt;T&gt;
  • 使用 C# 7 ValueTuple 时,现在可以缩短一点:foreach (var (x, i) in someCollection.Select((x, i) =&gt; (x, i)) ) { ... }
【解决方案3】:

C# foreach 没有内置索引。您需要在 foreach 循环之外添加一个整数并每次递增。

int i = -1;
foreach (Widget w in widgets)
{
   i++;
   // do something
}

或者,您可以使用标准 for 循环,如下所示:

for (int i = 0; i < widgets.Length; i++)
{
   w = widgets[i];
   // do something
}

【讨论】:

  • 我认为您应该将 i 初始化为 -1 并在循环体的开头将其递增,以确保“继续”语句不会导致问题。
  • @DrJokepu 为什么不简单地保持 i = 0 并在 foreach 语句的右括号之前增加它?当您稍后浏览代码时,使用 something != 0 进行初始化会引发注意...
  • 在 javascript 中工作
【解决方案4】:

我喜欢能够使用foreach,所以我做了一个扩展方法和一个结构:

public struct EnumeratedInstance<T>
{
    public long cnt;
    public T item;
}

public static IEnumerable<EnumeratedInstance<T>> Enumerate<T>(this IEnumerable<T> collection)
{
    long counter = 0;
    foreach (var item in collection)
    {
        yield return new EnumeratedInstance<T>
        {
            cnt = counter,
            item = item
        };
        counter++;
    }
}

还有一个使用示例:

foreach (var ii in new string[] { "a", "b", "c" }.Enumerate())
{
    Console.WriteLine(ii.item + ii.cnt);
}

一件好事是,如果你习惯了 Python 语法,你仍然可以使用它:

foreach (var ii in Enumerate(new string[] { "a", "b", "c" }))

【讨论】:

  • 最后一点的哪一部分看起来像 Python 语法?
  • 对不起,necropost。我修改了你的函数,使它看起来很漂亮,而且在使用中更加 Pythonic:pastebin.com/aExvenyY
【解决方案5】:

除了已经给出的 LINQ 答案之外,我还有一个 "SmartEnumerable" 类,它允许您获取索引和“第一个/最后一个”-ness。它在语法方面有点难看,但你可能会发现它很有用。

我们或许可以在非泛型类型中使用静态方法来改进类型推断,隐式类型也会有所帮助。

【讨论】:

  • 太棒了!这些小的辅助属性(first/last/index)应该包含在标准的 .net 框架中!
  • 太棒了,我只是不喜欢它冗长且不具描述性的名称
【解决方案6】:

我的解决方案涉及我为通用实用程序创建的一个简单的 Pair 类,它在操作上与框架类 KeyValuePair 基本相同。然后我为 IEnumerable 创建了几个扩展函数,称为 Ordinate(来自集合论术语“ordinal”)。

这些函数将为每个项目返回一个包含索引的 Pair 对象和项目本身。

public static IEnumerable<Pair<Int32, X>> Ordinate<X>(this IEnumerable<X> lhs)
{
    return lhs.Ordinate(0);
}

public static IEnumerable<Pair<Int32, X>> Ordinate<X>(this IEnumerable<X> lhs, Int32 initial)
{
    Int32 index = initial - 1;

    return lhs.Select(x => new Pair<Int32, X>(++index, x));
}

【讨论】:

  • 请注意,现在您的Pair 有一个System.Tuple
【解决方案7】:

不,没有。

正如其他人所展示的,有一些方法可以模拟 Ruby 的行为。但也有可能有一个实现了IEnumerable 的类型不公开索引。

【讨论】:

    【解决方案8】:

    这是你的收藏

    var values = new[] {6, 2, 8, 45, 9, 3, 0};
    

    为此集合创建一系列索引

    var indexes = Enumerable.Range(0, values.Length).ToList();
    

    使用范围与索引进行迭代

    indexes.ForEach(i => values[i] += i);
    indexes.ForEach(i => Console.Write("[{0}] = {1}", i, values[i]));
    

    【讨论】:

      【解决方案9】:

      我刚刚找到了有趣的解决方案:

      public class DepthAware<T> : IEnumerable<T>
      {
          private readonly IEnumerable<T> source;
      
          public DepthAware(IEnumerable<T> source)
          {
              this.source = source;
              this.Depth = 0;
          }
      
          public int Depth { get; private set; }
      
          private IEnumerable<T> GetItems()
          {
              foreach (var item in source)
              {
                  yield return item;
                  ++this.Depth;
              }
          }
      
          public IEnumerator<T> GetEnumerator()
          {
              return GetItems().GetEnumerator();
          }
      
          IEnumerator IEnumerable.GetEnumerator()
          {
              return GetEnumerator();
          }
      }
      
      // Generic type leverage and extension invoking
      public static class DepthAware
      {
          public static DepthAware<T> AsDepthAware<T>(this IEnumerable<T> source)
          {
              return new DepthAware<T>(source);
          }
      
          public static DepthAware<T> New<T>(IEnumerable<T> source)
          {
              return new DepthAware<T>(source);
          }
      }
      

      用法:

      var chars = new[] {'a', 'b', 'c', 'd', 'e', 'f', 'g'}.AsDepthAware();
      
      foreach (var item in chars)
      {
          Console.WriteLine("Char: {0}, depth: {1}", item, chars.Depth);
      }
      

      【讨论】:

      • 复活一个僵尸,因为我只需要这个:如果可枚举多次迭代,这将表现得令人困惑。
      • 你是对的。如果我今天要实现这一点,我肯定会接受公认的答案。
      【解决方案10】:

      这取决于你使用的类。

      Dictionary)>) 类例子支持这个

      Dictionary)>) 泛型类提供从一组键到一组值的映射。

      出于枚举的目的,字典中的每个项目都被视为表示值及其键的 KeyValuePair)>) 结构。返回项目的顺序未定义。

      foreach(myDictionary 中的 KeyValuePair kvp){...}

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-05-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-18
        相关资源
        最近更新 更多