2011-09-12 2 views
4

Не удалось найти соответствующий вопрос.Есть ли эквивалент перечисления Python для .NET IEnumerable

В python вы можете легко перебрать последовательность (list, generator и т.д.) и собирать индекс итерации в то же время благодаря 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() .. но если он существует, то я предпочел бы использовать его :))

UPDATE FYI, мне интересно об этом вид возможности быть в состоянии сделать что-то вроде: «дайте мне индекс последнего элемента, который выполняет это условие», которое затем будет достигнуто через:

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

ответ

3

Вместо того, чтобы использовать Tuple<,> (который является class) вы можете использовать KeyValuePair<,>, который является структурой. Это позволит избежать выделения памяти при перечислении (не то, чтобы они были очень дорогими, но все же).

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

спасибо, это на самом деле то, что я использую прямо сейчас, но он чувствует себя немного неудобно (особенно когда написан на VB.NET ... но какой код с участием дженериков в VB.NET выглядит красиво?) – tsimbalar

+0

, чтобы проиллюстрировать: 'Dim lastAccountDiscountIndex = availableDiscounts.Выберите (Function (d, i) Новый KeyValuePair (из GlobalDiscountDefaultValue, Int32) (d, i)) _ .Last (функция (kvp) kvp.Key.Source.Type = GlobalDiscountSourceType.QuotationAccount) _ .Value' – tsimbalar

+1

Well , не используйте VB.NET, тогда;) - Я знаю, что это не очень конструктивно, но VB.NET имеет основные недостатки синтаксиса IMHO в дженериках. BTW, с .NET 4, символ объединения '' 'больше не требуется во всех случаях] (http://www.simple-talk.com/dotnet/visual-studio/visual-studio-vb-2010 -укрепления /), вы должны иметь возможность, по крайней мере, отказаться от них. – Lucero

4

что касается конкретной функции, которая будет делать то, что Я спрашиваю, я не знаю, включает ли .NET. Самый быстрый способ, однако, было бы просто сделать что-то вроде этого:

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

EDIT: Вот функция, которая будет делать, спросите вы, используя 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++; 
    } 
} 
+0

+1 для 'yield' возврата, который, я полагаю, это то же самое, возвращая что-то в функции в 'Select()' метод. (см. мой ответ ниже, инкремент индекса выполняется для вас в одной из подписей 'Select()') – tsimbalar

+0

Я буду отмечать ключ KeyValuePair как ответ из-за объекта struct vs class. Но спасибо за это :-) – tsimbalar

2

Вот мой собственный ответ на мой собственный вопрос ...

Если он не существует, я мог бы также сделать это так, без фактического написания 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 

Это один лайнер ... уродливый один, но один вкладыш в любом случае :)

0

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}"); 
    } 
} 
Смежные вопросы