Foreach с индексом

Есть ли эквивалент С# для Python enumerate() и Ruby each_with_index?

Ответ 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;
});

Ответ 2

Вы можете сделать следующее

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

Это создаст значение анонимного типа для каждой записи в коллекции. У него будет два свойства

  • Value: с исходным значением в коллекции
  • Index: с указателем в коллекции

Ответ 3

С# foreach не имеет встроенного индекса. Вам нужно будет добавить целое число вне цикла foreach и увеличивать его каждый раз.

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

В качестве альтернативы вы можете использовать стандарт для цикла следующим образом:

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

Ответ 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" }))

Ответ 5

Помимо уже полученных ответов LINQ, у меня есть класс "SmartEnumerable", который позволяет вам получить индекс и "первый/последний" -ness. Это немного уродливо с точки зрения синтаксиса, но вы можете найти это полезным.

Вероятно, мы можем улучшить вывод типов, используя статический метод неуниверсального типа, и неявная типизация тоже поможет.

Ответ 6

Мое решение включает в себя простой класс Pair, который я создал для общей утилиты, и который по сути является тем же самым, что и класс framework 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));
}

Ответ 7

Нет, нет.

Как показали другие люди, существуют способы имитировать поведение Ruby. Но возможно иметь тип, который реализует IEnumerable, который не предоставляет индекс.

Ответ 8

Я просто вычислил интересное решение:

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

Ответ 9

Это ваша коллекция

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]));

Ответ 10

Это зависит от класса, который вы используете.

Словарь < (Of < (TKey, TValue > ) > ) Класс для примера Поддержка Это

Универсальный класс Dictionary < (Of < (TKey, TValue > ) > ) предоставляет отображение из набора ключей в набор значений.

Для целей перечисления каждый элемент словаря рассматривается как структура KeyValuePair < (Of < (TKey, TValue > ) > ), представляющая значение и его ключ. Порядок возврата элементов undefined.

foreach (KeyValuePair kvp в myDictionary) {...}