c# collections filtering

list where c#



Filtrado de colecciones en C# (9)

Si estás usando C # 3.0 puedes usar linq

O, si lo prefiere, use la sintaxis de consulta especial proporcionada por el compilador C # 3:

var filteredList = from x in myList where x > 7 select x;

Estoy buscando una forma muy rápida de filtrar una colección en C #. Actualmente estoy usando colecciones genéricas de Lista <objeto>, pero estoy abierto a usar otras estructuras si funcionan mejor.

Actualmente, estoy creando un nuevo List <object> y haciendo un looping a través de la lista original. Si el criterio de filtrado coincide, coloco una copia en la nueva lista.

¿Hay una mejor manera de hacer esto? ¿Hay alguna manera de filtrar en su lugar por lo que no se requiere una lista temporal?


Aquí hay un bloque de código / ejemplo de algunos filtros de listas usando tres métodos diferentes que preparé para mostrar el filtrado de listas basado en Lambda y LINQ.

#region List Filtering static void Main(string[] args) { ListFiltering(); Console.ReadLine(); } private static void ListFiltering() { var PersonList = new List<Person>(); PersonList.Add(new Person() { Age = 23, Name = "Jon", Gender = "M" }); //Non-Constructor Object Property Initialization PersonList.Add(new Person() { Age = 24, Name = "Jack", Gender = "M" }); PersonList.Add(new Person() { Age = 29, Name = "Billy", Gender = "M" }); PersonList.Add(new Person() { Age = 33, Name = "Bob", Gender = "M" }); PersonList.Add(new Person() { Age = 45, Name = "Frank", Gender = "M" }); PersonList.Add(new Person() { Age = 24, Name = "Anna", Gender = "F" }); PersonList.Add(new Person() { Age = 29, Name = "Sue", Gender = "F" }); PersonList.Add(new Person() { Age = 35, Name = "Sally", Gender = "F" }); PersonList.Add(new Person() { Age = 36, Name = "Jane", Gender = "F" }); PersonList.Add(new Person() { Age = 42, Name = "Jill", Gender = "F" }); //Logic: Show me all males that are less than 30 years old. Console.WriteLine(""); //Iterative Method Console.WriteLine("List Filter Normal Way:"); foreach (var p in PersonList) if (p.Gender == "M" && p.Age < 30) Console.WriteLine(p.Name + " is " + p.Age); Console.WriteLine(""); //Lambda Filter Method Console.WriteLine("List Filter Lambda Way"); foreach (var p in PersonList.Where(p => (p.Gender == "M" && p.Age < 30))) //.Where is an extension method Console.WriteLine(p.Name + " is " + p.Age); Console.WriteLine(""); //LINQ Query Method Console.WriteLine("List Filter LINQ Way:"); foreach (var v in from p in PersonList where p.Gender == "M" && p.Age < 30 select new { p.Name, p.Age }) Console.WriteLine(v.Name + " is " + v.Age); } private class Person { public Person() { } public int Age { get; set; } public string Name { get; set; } public string Gender { get; set; } } #endregion


El uso de Linq es relativamente más lento que el uso de un predicado suministrado al método Lists FindAll. También debe tener cuidado con Linq ya que la enumeración de la lista no se ejecuta realmente hasta que accede al resultado. Esto puede significar que cuando crea que ha creado una lista filtrada, el contenido puede diferir de lo que esperaba cuando realmente lo leyó.


La lista tiene el método FindAll que hará el filtrado por usted y devolverá un subconjunto de la lista.

El msdn tiene un excelente ejemplo de código aquí: http://msdn.microsoft.com/en-us/library/aa701359(VS.80).aspx

EDITAR: Escribí esto antes de tener una buena comprensión de Linq y el método Where (). Si tuviera que escribir esto hoy probablemente usaría el método que Jorge menciona arriba. El método FindAll todavía funciona si estás atrapado en un entorno .NET 2.0.


Para hacerlo en su lugar, puede usar el método RemoveAll de la clase "List <>" junto con una clase personalizada "Predicate" ... pero todo lo que hace es limpiar el código ... bajo el capó está haciendo lo mismo Lo que eres ... pero sí, lo hace en su lugar, por lo que haces lo mismo la lista temporal.


Puede usar IEnumerable para eliminar la necesidad de una lista temporal.

public IEnumerable<T> GetFilteredItems(IEnumerable<T> collection) { foreach (T item in collection) if (Matches<T>(item)) { yield return item; } }

donde coincide es el nombre de su método de filtro. Y puedes usar esto como:

IEnumerable<MyType> filteredItems = GetFilteredItems(myList); foreach (MyType item in filteredItems) { // do sth with your filtered items }

Esto llamará a la función GetFilteredItems cuando sea necesario y, en algunos casos, si no usa todos los elementos de la colección filtrada, puede proporcionar una buena ganancia de rendimiento.


Puede usar el método FindAll de la Lista, proporcionando un delegado para filtrar. Sin embargo, estoy de acuerdo con @ IainMH que no vale la pena preocuparse demasiado a menos que sea una lista enorme.


Si está usando C # 3.0 puede usar linq, mucho mejor y mucho más elegante:

List<int> myList = GetListOfIntsFromSomewhere(); // This will filter out the list of ints that are > than 7, Where returns an // IEnumerable<T> so a call to ToList is required to convert back to a List<T>. List<int> filteredList = myList.Where( x => x > 7).ToList();


Si su lista es muy grande y está filtrando repetidamente, puede ordenar la lista original en el atributo de filtro, búsqueda binaria para encontrar los puntos de inicio y fin.

Hora inicial O (n * log (n)) luego O (log (n)).

El filtrado estándar tomará O (n) cada vez.