繁体   English   中英

对于 .NET IEnumerable,是否有等效于 Python 的 enumerate()

[英]Is there an equivalent to Python's enumerate() for .NET IEnumerable

我找不到相关的问题。

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()中的正确 function ..但如果它存在,我宁愿使用它:))

更新仅供参考,我很好奇这种能够执行类似操作的可能性:“给我满足此条件的最后一项的索引”,然后通过以下方式完成:

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

至于能够做你所要求的特定功能,我不知道.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++;
    }
}

您可以使用KeyValuePair<,>作为结构KeyValuePair<,>而不是使用Tuple<,> (这是一个类)。 这将在枚举时避免内存分配(不是它们非常昂贵,但仍然如此)。

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

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}");
    }
}

以下是我对自己问题的回答......

如果它不存在,我不妨这样做,而不是实际写一个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

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

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

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") }

ZipEnumerable.Range一起使用怎么样?

var list = new List<string> { "toto", "titi", "tutu" };
foreach (var (str, i) in list.Zip(Enumerable.Range(0, int.MaxValue)))
{
    Console.WriteLine(i + " " + str);
}

Output:

0 toto
1 titi
2 tutu

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM