Yo escribí esto:
public static class EnumerableExtensions
{
public static int IndexOf<T>(this IEnumerable<T> obj, T value)
{
return obj
.Select((a, i) => (a.Equals(value)) ? i : -1)
.Max();
}
public static int IndexOf<T>(this IEnumerable<T> obj, T value
, IEqualityComparer<T> comparer)
{
return obj
.Select((a, i) => (comparer.Equals(a, value)) ? i : -1)
.Max();
}
}
Pero no sé si ya existe, ¿verdad?
Max
enfoque es que a: sigue buscando yb: devuelve el último índice cuando hay duplicados (la gente suele esperar el primer índice)ToList()/FindIndex()
truco funciona mejorRespuestas:
El objetivo de sacar las cosas como IEnumerable es para que puedas iterar perezosamente sobre los contenidos. Como tal, no existe realmente un concepto de índice. Lo que estás haciendo realmente no tiene mucho sentido para un IEnumerable. Si necesita algo que admita el acceso por índice, colóquelo en una lista o colección real.
fuente
IEnumerable<>
. No compro todo el dogma "deberías estar haciendo esto".IEnumerable
entoncesEnumerable.ElementAt
no existiría.IndexOf
es simplemente lo inverso: cualquier argumento en contra debe aplicarse igualmente aElementAt
.Cuestionaría la sabiduría, pero tal vez:
(usando
EqualityComparer<T>.Default
para emular!=
si es necesario), pero necesita mirar para devolver -1 si no se encuentra ... así que tal vez solo hágalo a la largafuente
TakeWhile
¡es inteligente! Tenga en cuenta que esto regresaCount
si el elemento no existe, lo cual es una desviación del comportamiento estándar.Lo implementaría así:
fuente
==
podría necesitar trabajo?KVP<T, int?>
(índice anulable)IList<T>
y, en caso afirmativo, diferir a su método IndexOf en caso de que tenga una optimización de tipo específico.La forma en que lo estoy haciendo actualmente es un poco más corta que las ya sugeridas y, por lo que puedo decir, da el resultado deseado:
Es un poco torpe, pero hace el trabajo y es bastante conciso.
fuente
La mejor manera de tomar la posición es
FindIndex
Esta función está disponible solo paraList<>
Ejemplo
Si tiene enumerador o matriz, use de esta manera
o
fuente
Creo que la mejor opción es implementar así:
Tampoco creará el objeto anónimo
fuente
Un poco tarde en el juego, lo sé ... pero esto es lo que hice recientemente. Es ligeramente diferente al suyo, pero permite que el programador dicte lo que la operación de igualdad debe ser (predicado). Lo cual encuentro muy útil cuando trato con diferentes tipos, ya que tengo una forma genérica de hacerlo independientemente del tipo de objeto y del
<T>
operador de igualdad incorporado.También tiene una huella de memoria muy pequeña, y es muy, muy rápido / eficiente ... si te importa eso.
En el peor de los casos, solo agregará esto a su lista de extensiones.
De todos modos ... aquí está.
Esperemos que esto ayude a alguien.
fuente
GetEnumerator
y enMoveNext
lugar de solo unforeach
?foreach
llamaráDispose
al enumerador si se implementaIDisposable
. (Consulte stackoverflow.com/questions/4982396/… ) Como el código en esta respuesta no sabe si el resultado de la llamadaGetEnumerator
es o no desechable, debería hacer lo mismo. En ese momento todavía no estoy claro si hay un beneficio de rendimiento, ¡aunque hubo una IL adicional cuyo propósito no se me ocurrió!foreach
bucle, en cuyo caso para el caso particular deT
al ser un tipo de valor, podría estar guardando una operación de caja / caja utilizando el bucle while. Sin embargo, esto no es confirmado por el IL que obtuve de una versión de su respuestaforeach
. Sin embargo, sigo pensando que la eliminación condicional del iterador es importante. ¿Podría modificar la respuesta para incluir eso?Unos años más tarde, pero esto usa Linq, devuelve -1 si no se encuentra, no crea objetos adicionales y debería cortocircuitarse cuando se encuentra [en lugar de iterar sobre todo IEnumerable]:
Donde 'FirstOr' es:
fuente
source.Where
ysource.DefaultIfEmpty
, por ejemplo, crearán unIEnumerable
cada uno.Encontré esto hoy en busca de respuestas y pensé en agregar mi versión a la lista (sin juego de palabras). Utiliza el operador condicional nulo de c # 6.0
He hecho algunas 'carreras de los viejos caballos' (pruebas) y para grandes colecciones (~ 100,000), el peor de los casos en que el artículo que deseas es al final, esto es 2 veces más rápido que hacerlo
ToList().FindIndex()
. Si el artículo que desea está en el medio, es ~ 4 veces más rápido.Para colecciones más pequeñas (~ 10,000) parece ser solo marginalmente más rápido
Aquí está cómo lo probé https://gist.github.com/insulind/16310945247fcf13ba186a45734f254e
fuente
Usando la respuesta de @Marc Gravell, encontré una manera de usar el siguiente método:
para obtener -1 cuando no se puede encontrar el artículo:
Supongo que de esta manera podría ser tanto el más rápido como el más simple. Sin embargo, aún no he probado las actuaciones.
fuente
Una alternativa para encontrar el índice después del hecho es envolver el Enumerable, algo similar a usar el método Linq GroupBy ().
Lo que da un caso de uso de:
fuente
Esto puede ser realmente genial con una extensión (que funciona como un proxy), por ejemplo:
Que asignará automáticamente índices a la colección accesible a través de este
Index
propiedad.Interfaz:
Extensión personalizada (probablemente más útil para trabajar con EF y DbContext):
fuente