c# - indice - foreach con índice
indice de foreach c# (10)
Esta pregunta ya tiene una respuesta aquí:
¿Hay un equivalente de C # de enumerate()
de Python y each_with_index
de Ruby?
Acabo de descubrir una solución interesante:
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);
}
}
Uso:
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);
}
Además de las respuestas de LINQ ya dadas, tengo una clase "SmartEnumerable" que te permite obtener el índice y el "first / last" -ness. Es un poco feo en términos de sintaxis, pero puede que le resulte útil.
Probablemente podamos mejorar la inferencia tipo utilizando un método estático en un tipo no genérico, y la tipificación implícita también ayudará.
Depende de la clase que estés usando.
Diccionario <(Of <(TKey, TValue>)>) Class for Example Support This
La clase genérica Dictionary <(Of <(TKey, TValue>)>) proporciona una asignación de un conjunto de claves a un conjunto de valores.
A los fines de la enumeración, cada elemento del diccionario se trata como una estructura KeyValuePair <(Of <(TKey, TValue>)>) que representa un valor y su clave. El orden en que se devuelven los artículos no está definido.
foreach (KeyValuePair kvp en myDictionary) {...}
El foreach de C # no tiene un índice incorporado. Necesitará agregar un número entero fuera del ciclo foreach e incrementarlo cada vez.
int i = -1;
foreach (Widget w in widgets)
{
i++;
// do something
}
Alternativamente, puede usar un ciclo for para lo siguiente:
for (int i = 0; i < widgets.Length; i++)
{
w = widgets[i];
// do something
}
Esta es tu colección
var values = new[] {6, 2, 8, 45, 9, 3, 0};
Haga una variedad de índices para esta colección
var indexes = Enumerable.Range(0, values.Length).ToList();
Usa el rango para iterar con el índice
indexes.ForEach(i => values[i] += i);
indexes.ForEach(i => Console.Write("[{0}] = {1}", i, values[i]));
Guardo este método de extensión para esto:
public static void Each<T>( this IEnumerable<T> ie, Action<T, int> action )
{
var i = 0;
foreach ( var e in ie ) action( e, i++ );
}
Y úsalo así:
var strings = new List<string>();
strings.Each( ( str, n ) =>
{
// hooray
} );
O para permitir el comportamiento de 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;
} );
Me gusta poder usar foreach, así que hice un método de extensión y una estructura:
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++;
}
}
y un uso de ejemplo:
foreach (var ii in new string[] { "a", "b", "c" }.Enumerate())
{
Console.WriteLine(ii.item + ii.cnt);
}
Una cosa buena es que si estás acostumbrado a la sintaxis de Python, aún puedes usarla:
foreach (var ii in Enumerate(new string[] { "a", "b", "c" }))
Mi solución implica una clase simple de par que creé para la utilidad general, y que es operativamente esencialmente la misma que la clase de marco KeyValuePair. Luego creé un par de funciones de extensión para IEnumerable denominadas Ordinate (del término de la teoría de conjuntos " ordinal ").
Estas funciones devolverán para cada elemento un objeto Pair que contenga el índice y el artículo mismo.
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));
}
No no hay.
Como han demostrado otras personas, hay formas de simular el comportamiento de Ruby. Pero es posible tener un tipo que implemente IEnumerable que no exponga un índice.
Puedes hacer lo siguiente
foreach ( var it in someCollection.Select((x,i) => new { Value = x, Index=i }) )
{
if ( it.Index > SomeNumber) //
}
Esto creará un valor de tipo anónimo para cada entrada del recopilador. Tendrá dos propiedades
- Valor: con el valor original en la colección
- Índice: con el índice dentro de la colección