Tengo un foreach
bucle y necesito ejecutar algo de lógica cuando se elige el último elemento List
, por ejemplo:
foreach (Item result in Model.Results)
{
//if current result is the last item in Model.Results
//then do something in the code
}
¿Puedo saber qué ciclo es el último sin usar para ciclo y contadores?
Respuestas:
Si solo necesita hacer algo con el último elemento (a diferencia de algo diferente con el último elemento, usar LINQ lo ayudará aquí:
Si necesita hacer algo diferente con el último elemento, necesitaría algo como:
Aunque es probable que necesite escribir un comparador personalizado para asegurarse de que pueda decir que el artículo fue el mismo que devolvió el artículo
Last()
.Este enfoque debe usarse con precaución, ya que es
Last
posible que tenga que iterar a través de la colección. Si bien esto podría no ser un problema para las colecciones pequeñas, si se hace grande podría tener implicaciones de rendimiento. También fallará si la lista contiene elementos duplicados. En estos casos, algo como esto puede ser más apropiado:fuente
var last = Model.Result[Model.Result.Count - 1];
más rápido que usarLast()
¿Qué tal un buen bucle pasado de moda?
O usando Linq y el foreach:
fuente
Model.Results
es unIEnumerable
. Puede llamarCount()
antes del ciclo pero eso puede causar la iteración completa de la secuencia.¡El uso
Last()
en ciertos tipos recorrerá toda la colección!Lo que significa que si haces una
foreach
llamada yLast()
llamaste dos veces. que estoy seguro de que te gustaría evitar en grandes colecciones.Entonces la solución es usar un
do while
bucle:Entonces, a menos que el tipo de colección sea de tipo,
IList<T>
laLast()
función iterará a través de todos los elementos de la colección.Prueba
Si su colección proporciona acceso aleatorio (por ejemplo, implementos
IList<T>
), también puede verificar su artículo de la siguiente manera.fuente
using
declaración? Pensé que solo era necesario si un objeto maneja los recursos del sistema operativo, pero no para las estructuras de datos administrados.Como muestra Chris, Linq funcionará; solo use Last () para obtener una referencia al último en el enumerable, y siempre que no esté trabajando con esa referencia, entonces haga su código normal, pero si ESTÁ trabajando con esa referencia, haga su trabajo adicional. Su desventaja es que siempre será una complejidad O (N).
En su lugar, puede usar Count () (que es O (1) si IEnumerable también es una ICollection; esto es cierto para la mayoría de los IEnumerables incorporados comunes) e híbrir su foreach con un contador:
fuente
fuente
foreach
bloqueo. De esta manera:var lastItem = objList.LastOrDeafault();
. A continuación, desde el interior delforeach
bucle se puede comprobar de esta manera:f (item.Equals(lastItem)) { ... }
. En su respuesta originalobjList.LastOrDefault()
, iteraría sobre la colección en cada iteración "foreach" (la complejidad polinomial está involucrada ).Como Shimmy ha señalado, usar Last () puede ser un problema de rendimiento, por ejemplo, si su colección es el resultado en vivo de una expresión LINQ. Para evitar múltiples iteraciones, puede usar un método de extensión "ForEach" como este:
El método de extensión se ve así (como una ventaja adicional, también le indicará el índice y, si está viendo el primer elemento):
fuente
Mejorando aún más la respuesta de Daniel Wolf , podría apilarse en otra
IEnumerable
para evitar múltiples iteraciones y lambdas como:La implementación del método de extensión:
fuente
foreach
, que es una mejora.La implementación del iterador no proporciona eso. Su colección puede ser
IList
accesible mediante un índice en O (1). En ese caso, puede usar unfor
bucle normal :Si conoce el recuento, pero no puede acceder a través de los índices (por lo tanto, el resultado es un
ICollection
), puede contar usted mismo incrementando uni
en elforeach
cuerpo y comparándolo con la longitud.Todo esto no es perfectamente elegante. La solución de Chris puede ser la mejor que he visto hasta ahora.
fuente
¿Qué pasa con un enfoque poco más simple?
fuente
El mejor enfoque probablemente sería simplemente ejecutar ese paso después del ciclo: por ejemplo
O si necesita hacer algo para el último resultado
fuente
La respuesta aceptada no funcionará para duplicados en la colección. Si está configurado en
foreach
, simplemente puede agregar sus propias variables de indexación.fuente
usando Linq y el foreach:
https://code.i-harness.com/en/q/7213ce
fuente
".Last ()" no funcionó para mí, así que tuve que hacer algo como esto:
fuente
Haciendo algunos pequeños ajustes al excelente código de Jon Skeet, incluso puede hacerlo más inteligente al permitir el acceso al elemento anterior y siguiente. Por supuesto, esto significa que tendrá que leer con anticipación 1 elemento en la implementación. Por razones de rendimiento, el elemento anterior y el siguiente solo se retienen para el elemento de iteración actual. Dice así:
fuente
Cómo convertir
foreach
para reaccionar al último elemento:fuente
Simplemente almacene el valor anterior y trabaje con él dentro del ciclo. Luego, al final, el valor 'anterior' será el último elemento, lo que le permitirá manejarlo de manera diferente. No se requieren conteo ni bibliotecas especiales.
fuente
Puede usar un bucle for y no es necesario agregar un extra
if
dentro delfor
cuerpo:El
-1
en lafor
condición se encarga de omitir el último elemento.fuente
Jon Skeet creó un
SmartEnumerable<T>
tipo hace un tiempo para resolver este problema exacto. Puedes ver su implementación aquí:http://codeblog.jonskeet.uk/2007/07/27/smart-enumerations/
Para descargar: http://www.yoda.arachsys.com/csharp/miscutil/
fuente
Para hacer algo adicional a cada elemento, excepto el último, se puede utilizar el enfoque basado en funciones.
Este enfoque tiene inconvenientes aparentes: menos claridad de código para casos más complejos. Llamar a los delegados podría no ser muy efectivo. La resolución de problemas podría no ser tan fácil. El lado positivo: ¡la codificación es divertida!
Dicho esto, sugeriría usar plain for loops en casos triviales, si sabes que el recuento de tu colección no es terriblemente lento.
fuente
Otra forma, que no vi publicada, es usar una cola. Es análogo a una forma de implementar un método SkipLast () sin iterar más de lo necesario. De esta manera también le permitirá hacer esto en cualquier número de últimos elementos.
Para llamar a esto, haría lo siguiente:
fuente
fuente
Puede hacer un método de extensión especialmente dedicado a esto:
y puedes usarlo así:
fuente
Basado en la respuesta de @ Shimmy, creé un método de extensión que es la solución que todos quieren. Es simple, fácil de usar y solo recorre la colección una vez.
Esto funciona en cualquiera
IEnumerable<T>
. El uso se ve así:La salida se ve así:
Además, puede convertir esto en un
Select
método de estilo. Luego, reutilice esa extensión enForEach
. Ese código se ve así:fuente
Podemos verificar el último elemento en bucle.
fuente
fuente
Puedes hacer así:
fuente