【问题标题】:Is there an equivalent to Python's enumerate() for .NET IEnumerable.NET IEnumerable 是否有相当于 Python 的 enumerate()
【发布时间】:2011-09-12 13:56:30
【问题描述】:

我找不到相关问题。

python 中,您可以轻松地遍历一个序列(listgenerator 等)并同时收集迭代的索引,这要感谢enumerate(seq),就像这样:

>>> for (i,item) in enumerate(["toto","titi","tutu"]):
...     print i, item
...
0 toto
1 titi
2 tutu

IEnumerable 是否有类似的东西,例如,将 IEnumerable<T> 转换为 IEnumerable<Tuple<Int32,T>>

(由于Select() 中的正确功能,我知道这很容易完成......但如果它存在,我宁愿使用它:))

更新 仅供参考,我很好奇这种可能性能够做类似的事情:“给我满足这个条件的最后一个项目的索引”,然后通过:

myEnumeration.First(t => some condition on t.Item2 ... ).Item1;

【问题讨论】:

标签: .net ienumerable


【解决方案1】:

C# 7 最终允许您以优雅的方式做到这一点:

static class Extensions
{
    public static IEnumerable<(int, T)> Enumerate<T>(
        this IEnumerable<T> input,
        int start = 0
    )
    {
        int i = start;
        foreach (var t in input)
            yield return (i++, t);
    }
}

class Program
{
    static void Main(string[] args)
    {
        var s = new string[]
        {
            "Alpha",
            "Bravo",
            "Charlie",
            "Delta"
        };

        foreach (var (i, o) in s.Enumerate())
            Console.WriteLine($"{i}: {o}");
    }
}

【讨论】:

    【解决方案2】:

    您可以使用 KeyValuePair&lt;,&gt; 结构,而不是使用 Tuple&lt;,&gt;(这是一个类)。这将避免枚举时的内存分配(不是说它们非常昂贵,但仍然如此)。

    public static IEnumerable<KeyValuePair<int, T>> Enumerate<T>(this IEnumerable<T> items) {
        return items.Select((item, key) => new KeyValuePair(key, item));
    }
    

    【讨论】:

    • 谢谢,这实际上是我现在正在使用的,但感觉有点尴尬(特别是用VB.NET编写时......但是VB.NET中涉及泛型的代码看起来不错?)
    • 说明:Dim lastAccountDiscountIndex = availableDiscounts.Select(Function(d, i) New KeyValuePair(Of GlobalDiscountDefaultValue, Int32)(d, i)) _ .Last(Function(kvp) kvp.Key.Source.Type = GlobalDiscountSourceType.QuotationAccount) _ .Value
    • 好吧,那就不要使用 VB.NET ;) - 我知道这不是很有建设性,但 VB.NET 在泛型中存在重大语法缺陷恕我直言。顺便说一句,从 .NET 4 开始,_ line combining character is no longer required in all cases,您至少应该能够删除这些。
    • 我希望我有一个选择 :'( 。实际上在这种情况下我不能删除那些下划线。如果我想在每行的末尾保留点,并且方法在关注一个,但对我来说它看起来不对......
    • 是的,我虽然是这样(你没有选择)。无论如何,与连续字符和行首的点相比,我更喜欢行尾的点(无论如何这是我的风格 g)。很抱歉没有提供更多帮助。
    【解决方案3】:

    至于可以满足您要求的特定功能,我不知道 .NET 是否包含它。然而,最快的方法就是这样做:

    int id = 0;
    foreach(var elem in someList)
    {
        ... doStuff ...
        id++;
    }
    

    编辑:这是一个可以按照您的要求使用 yield return 的函数,但它的缺点是每次迭代都需要分配一次 GC:

    public static IEnumerable<Tuple<int, T>> Enumerate<T>(IEnumerable<T> list)
    {
        int id = 0;
        foreach(var elem in list)
        {
            yield return new Tuple<int, T>(id, elem);
            id++;
        }
    }
    

    【讨论】:

    • +1 表示 yield 返回,我认为这与在 Select() 方法中返回函数中的内容相同。 (请参阅下面我的回答,索引的递增是在Select() 的签名之一中为您完成的)
    • 我将用 KeyValuePair 标记为答案,因为结构与类的关系。但是感谢这个:-)
    【解决方案4】:

    这是我对自己问题的回答......

    如果它不存在,我还不如这样做,而无需实际编写for/foreach

    var items = new List<String> { "toto", "titi", "tutu" };
    
    var enumerated = items.Select((x, i) => new Tuple<int, String>(i, x));
    
    foreach (var t in enumerated)
    {
        Console.WriteLine(String.Format("{0} : {1}", t.Item1, t.Item2));
    
    }
    

    哪个打印:

    0 : toto
    1 : titi
    2 : tutu
    

    这是一个单线......一个丑陋的,但无论如何都是一个单线:)

    【讨论】:

      【解决方案5】:

      这是一个扩展方法,它将返回元组序列,其中第一项是序列中的数字,第二项是源序列中的值。

      public static IEnumerable<Tuple<int, T>> Enumerate<T>(this IEnumerable<T> source, int start = 0)
      {
          return source.Select((value, index) => new Tuple<int, T>(index + start, value));
      }
      

      示例:

      var source = new[] { "apple", "pear", "banana", "orange", "lemon" };
      var enumerated1 = source.Enumerate();   // { (0, "apple"), (1, "pear"), (2, "banana"), (3, "orange"), (4, "lemon") }
      var enumerated2 = source.Enumerate(3);  // { (3, "apple"), (4, "pear"), (5, "banana"), (6, "orange"), (7, "lemon") }
      

      【讨论】:

      • 本网站上通常不赞成仅使用代码的答案。您能否编辑您的答案以包含一些 cmets 或对您的代码的解释?解释应回答以下问题:它有什么作用?它是如何做到的?它去哪儿了?它如何解决OP的问题?请参阅:How to anwser。谢谢!
      猜你喜欢
      • 2012-09-17
      • 2017-01-11
      • 1970-01-01
      • 1970-01-01
      • 2019-11-29
      • 1970-01-01
      • 2015-03-24
      • 2011-10-24
      • 2013-07-07
      相关资源
      最近更新 更多