Question

Je recherche un moyen très rapide de filtrer une collection en C#.J'utilise actuellement des collections génériques List<object>, mais je suis ouvert à l'utilisation d'autres structures si elles fonctionnent mieux.

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

Y a-t-il une meilleure manière de faire cela?Existe-t-il un moyen de filtrer afin qu'aucune liste temporaire ne soit requise ?

Était-ce utile?

La solution

Si vous utilisez C# 3.0, vous pouvez utiliser Linq, bien mieux et bien plus élégant :

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 vous ne trouvez pas le .Where, cela signifie que vous devez importer using System.Linq; en haut de votre fichier.

Autres conseils

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

List a la méthode FindAll qui effectuera le filtrage pour vous et renverra un sous-ensemble de la liste.

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

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

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.Et vous pouvez utiliser ceci comme :

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

Cela appellera la fonction GetFilteredItems en cas de besoin et dans certains cas où vous n'utilisez pas tous les éléments de la collection filtrée, cela peut fournir un bon gain de performances.

Vous pouvez utiliser le Trouver tout méthode de la liste, fournissant un délégué sur lequel filtrer.Cependant, je suis d'accord avec @IainMH que cela ne vaut pas la peine de trop s'inquiéter à moins que la liste ne soit énorme.

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

L'utilisation de Linq est relativement plus lente que l'utilisation d'un prédicat fourni à la méthode Lists FindAll.Il faut également être prudent avec Linq car l'eumération de la liste n'est réellement exécutée que lorsque vous accédez au résultat.Cela peut signifier que lorsque vous pensez avoir créé une liste filtrée, le contenu peut différer de ce à quoi vous vous attendiez lorsque vous l'avez réellement lu.

Si vous utilisez C# 3.0, vous pouvez utiliser Linq

Ou, si vous préférez, utilisez la syntaxe de requête spéciale fournie par le compilateur C# 3 :

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

Si votre liste est très longue et que vous filtrez à plusieurs reprises, vous pouvez trier la liste d'origine sur l'attribut de filtre, effectuer une recherche binaire pour trouver les points de début et de fin.

Heure initiale O(n*log(n)) puis O(log(n)).

Le filtrage standard prendra O(n) à chaque fois.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top