194 votes

Filtrer les collections en C#

Je cherche un moyen très rapide de filtrer une collection en C#. J'utilise actuellement la fonction générique List<object> mais je suis ouvert à l'utilisation d'autres structures si elles sont plus performantes.

Actuellement, je crée simplement un nouveau List<object> et de parcourir en boucle la liste d'origine. Si les critères de filtrage correspondent, je place une copie dans la nouvelle liste.

Existe-t-il une meilleure façon de procéder ? Existe-t-il un moyen de filtrer en place de sorte qu'aucune liste temporaire ne soit nécessaire ?

1 votes

Cela va être très rapide. Cela ralentit-il votre système ? Est-ce un énorme liste ? Sinon, je ne m'inquiéterais pas.

313voto

Jorge Córdoba Points 18919

Si vous utilisez C# 3.0, vous pouvez utiliser linq, qui est bien meilleur et bien plus élégant :

List<int> myList = GetListOfIntsFromSomewhere();

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

Si vous ne trouvez pas le .Where Cela signifie que vous devez importer using System.Linq; au début de votre fichier.

1 votes

Comment cela fonctionne-t-il pour le filtrage par chaînes. Par exemple, trouver tous les éléments d'une liste de chaînes qui commencent par "ch"

3 votes

@JonathanO Vous pouvez utiliser des méthodes à l'intérieur de Func. listOfStrings.Where(s => s.StartsWith("ch")).ToList() ;

1 votes

Existe-t-il un moyen d'objectiver les requêtes linq ? Par exemple, pour utiliser .Where(predefinedQuery) au lieu d'utiliser .Where(x => x > 7) ?

23voto

Jon Erickson Points 29643

Voici un bloc de code / exemple de filtrage de liste utilisant trois méthodes différentes que j'ai mis en place pour montrer les Lambdas et le filtrage de liste basé sur 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

21voto

Mykroft Points 4292

List<T> a une FindAll qui effectuera le filtrage pour vous et renverra un sous-ensemble de la liste.

MSDN propose un excellent exemple de code ici : http://msdn.microsoft.com/en-us/library/aa701359(VS.80).aspx

EDIT : J'ai écrit ceci avant d'avoir une bonne compréhension de LINQ et de la méthode Where() méthode. Si je devais écrire ce texte aujourd'hui, j'utiliserais probablement la méthode mentionnée par Jorge. La FindAll fonctionne toujours si vous êtes coincé dans un environnement .NET 2.0.

6 votes

Linq est bien, mais au moins une magnitude plus lente, donc FindAll et les méthodes d'extension de filtrage (array a un tas d'entre elles par exemple) qui ne reposent pas sur IEnumerable ont encore du sens pour les scénarios où la performance est importante. (A titre d'information, j'ai obtenu des résultats allant d'un facteur 7 à 50 de temps en plus pour Linq et/ou IEnumerable, en général).

0 votes

Y a-t-il une raison pour que cette réponse ne soit pas acceptée ? Elle semble plus rapide et la syntaxe est plus claire (pas d'appel à toList()) à la fin).

8voto

Serhat Özgel Points 10010

Vous pouvez utiliser IEnumerable pour éliminer le besoin d'une liste temporaire.

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

où Matches est le nom de votre méthode de filtrage. Vous pouvez utiliser cette méthode comme suit

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

Cela appellera la fonction GetFilteredItems lorsque cela sera nécessaire et dans certains cas où vous n'utilisez pas tous les éléments de la collection filtrée, cela peut permettre un gain de performance.

4voto

Adam Haile Points 12576

Pour le faire à la place, vous pouvez utiliser la méthode RemoveAll de la classe "List<>" avec une classe "Predicate" personnalisée... mais tout ce que cela fait, c'est nettoyer le code... sous le capot, il fait la même chose que vous... mais oui, il le fait à la place, donc vous faites la même chose que la liste temporaire.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X