Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

210
Vistas
¿Cómo iterar en los elementos de una sublista y luego eliminar la sublista de la lista? Con gran rendimiento

Este es un ejemplo: originalList es una lista de objetos

 var subList = (originalList.Where(x => x.number < 0)).ToList(); originalList.RemoveAll(x => x.number < 0);

Usaré la subList más tarde. En este ejemplo originaList se itera dos veces. Esta función se llama miles de millones de veces y originalList es una lista grande

¿Hay una manera fácil de mejorar el rendimiento?


Una cosa importante: el valor del número del objeto puede cambiar entre dos llamadas de esta función.

over 4 years ago · Santiago Trujillo
3 Respuestas
Responde la pregunta

0

Este método elimina todos los elementos que cumplen una condición y devuelve una lista de los elementos eliminados. Solo itera una vez.

 public static List<T> RemoveAll<T>(List<T> input, Func<T,bool> condition) { List<T> removedEntries = new List<T>(); int offset = 0; for(int i = 0; i < input.Count - offset; i++) { while(i < input.Count - offset && condition.Invoke(input[i + offset])) { removedEntries.Add(input[i + offset]); offset++; Console.WriteLine("i="+i+", offset="+offset); } if(i < input.Count - offset) { input[i] = input[i+offset]; } } input.RemoveRange(input.Count - offset, offset); return removedEntries; }

Recorremos la lista y comprobamos si un elemento coincide con la condición. Si la condición coincide, el elemento posterior a ese elemento se copia en la posición. Entonces, todos los elementos que no cumplan la condición estarán al principio de la lista, y todos los elementos que cumplan la condición estarán al final de la lista. En el último paso, se eliminan los elementos al final de la lista.

Puede ser conveniente dar una capacidad inicial a la lista de removedEntries . Por defecto, una lista tiene una capacidad de 4, que se duplica cada vez que se supera. Si tiene 100 elementos para eliminar, la capacidad debe ampliarse 5 veces. Esta es una operación O(n) cada vez. Si puede estimar que eliminará alrededor del 10% de los elementos, podría escribir

 List<T> removedEntries = new List<T>(input.Count / 10);

Esto podría ahorrarle algo de tiempo, pero por otro lado, si no necesita la capacidad inicial completa de la lista, desperdiciará algo de memoria.

Demostración en línea: https://dotnetfiddle.net/dlthkH

over 4 years ago · Santiago Trujillo Denunciar

0

Una mejora de la eficiencia (aunque en última instancia sigue siendo O(n)) es agrupar las eliminaciones por lotes. Mis pruebas muestran que, dependiendo de la frecuencia de eliminación, esta puede ser la misma velocidad o más de 4 veces más rápida. Aquí está la función como un método de extensión:

 public static List<T> RemoveAllAndReturn<T>(this List<T> input, Func<T, bool> condition) { List<T> result = new List<T>(); var removeCt = 0; for (int i = input.Count - 1; i >= 0; --i) { if (condition(input[i])) { result.Add(input[i]); ++removeCt; } else if (removeCt > 0) { input.RemoveRange(i + 1, removeCt); removeCt = 0; } } if (removeCt > 0) input.RemoveRange(0, removeCt); return result; }
over 4 years ago · Santiago Trujillo Denunciar

0

Podrías considerar hacer este truco:

 var subList = new List<SomeType>(); originalList.RemoveAll(x => { bool shouldBeRemoved = x.Number < 0; if (shouldBeRemoved) subList.Add(x); return shouldBeRemoved; });

El Predicate<T> pasado a RemoveAll no es puro: tiene el efecto secundario de insertar elementos coincidentes en la subList . Basado en la implementación del método RemoveAll , este truco debería funcionar como se esperaba. Sin embargo, la documentación no garantiza explícitamente que el predicado se invocará solo una vez por elemento:

Los elementos de List<T> actual se pasan individualmente al delegado de Predicate<T> y los elementos que coinciden con las condiciones se quitan de List<T> .

Así que haz tu propio juicio sobre si es seguro usar este truco o no.


Editar: también podría convertirlo en un método de extensión:

 public static int RemoveAll<T>(this List<T> source, Predicate<T> match, out List<T> removed) { var removedLocal = new List<T>(); removed = removedLocal; int removedCount = source.RemoveAll(x => { bool shouldBeRemoved = match(x); if (shouldBeRemoved) removedLocal.Add(x); return shouldBeRemoved; }); Debug.Assert(removedCount == removed.Count); return removedCount; }

Ejemplo de uso:

 originalList.RemoveAll(x => x.number < 0, out var subList);
over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda