Есть ли эквивалент C# для enumerate()
Python и Ruby's each_with_index
?foreach с индексом
ответ
C# 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
}
Я думаю, вы должны инициализировать i до -1 и увеличивать его в начале тела цикла, чтобы убедиться, что оператор «continue» не вызывает проблем. –
@DrJokepu почему бы не просто сохранить i = 0 и увеличить его до закрывающей скобки инструкции foreach? Инициализация с чем-то! = 0 вызывает внимание, когда вы позже просматриваете код ... – Adi
Это зависит от класса, который вы используете.
словарь < (Из < (TKey, TValue>)>) Класс Для примера поддержка Этот
Словарь < (Из < (TKey, TValue>)>) общий класс обеспечивает отображение из множества ключей к набору значений.
Для целей перечисления каждый элемент в словаре рассматривается как структура KeyValuePair < (Of < (TKey, TValue>)>), представляющая значение и его ключ. Порядок, в котором возвращаются элементы, не определен.
Еогеасп (KeyValuePair КВП в MyDictionary) {...}
Вы можете сделать следующее
foreach (var it in someCollection.Select((x,i) => new { Value = x, Index=i }))
{
if (it.Index > SomeNumber) //
}
Это позволит создать анонимное значение типа для каждой записи в сборном. Она будет иметь два свойства
- Value: с исходным значением в коллекции
- Индекса: с индексом в коллекции
Умный, но это похоже на почесывание левого уха правой рукой. Думаю, я просто буду держать индекс сам, поэтому я не путаю будущих сопровождающих. – Ken
A для усилий, но F для общей читаемости и обслуживания. Извините. –
@Neil, я поражен тем, что люди думают, что это проблема обеспечения. Эта перегрузка Select (и других методов LINQ) была предоставлена для полного Цель таких операций. – JaredPar
Помимо ответов LINQ уже данных, у меня есть "SmartEnumerable" класса который позволяет получить индекс и «первый/последний». Это немного уродливо с точки зрения синтаксиса, но вы можете найти его полезным.
Возможно, мы сможем улучшить вывод типа, используя статический метод в нежизнеспособном типе, и неявное типирование тоже поможет.
Отлично! Эти небольшие вспомогательные свойства (первый/последний/индекс) должны быть включены в стандартную инфраструктуру .net! –
Замечательно, мне просто не нравится его длинное и не описательное имя. –
Мое решение включает в себя простой класс Pair I, созданный для общей утилиты, и который по сути является тем же самым, что и класс 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));
}
Обратите внимание, что в наши дни существует 'System.Tuple' для вашей' Pair'. – Ashe
Нет, не существует.
Как показали другие люди, существуют способы имитировать поведение Руби. Но возможно иметь тип, который реализует IEnumerable, который не предоставляет индекс.
Я держу этот метод расширения вокруг этого:
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
-как поведение:
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. –
I просто вычислил интересное решение:
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);
}
Воскрешение зомби с тех пор, как я просто нуждался в этом: это будет вести себя смутно, если перечислимое будет повторяться несколько раз. – millimoose
Это ваша коллекция
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]));
Мне нравится быть в состоянии использовать Еогеасп, так что я сделал метод расширения и структуру:
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 для вас? – ArtOfWarfare
Извините за некропость. Я модифицировал вашу функцию, чтобы она выглядела красивой и более питонической: http://pastebin.com/aExvenyY – KgOfHedgehogs
Если вы используете LINQ, есть переопределения различных функций, которые допускают перечисление. В противном случае вы обычно застреваете, используя переменную, которую вы увеличиваете. – GWLlosa
Можем ли мы обновить этот вопрос до C# 7.0, где теперь есть кортежи? Интересно, как будет выглядеть решение с использованием кортежей. –
Является ли это особенностью 'foreach', что вы можете обрабатывать каждый элемент, который полностью отделен от его позиции в списке? –