web-dev-qa-db-fra.com

filtrer une liste en utilisant LINQ

j'ai une liste d'objets du projet:

IEnumerable<Project> projects

a Project class en tant que propriété appelée Tags . c'est un int []

j'ai une variable appelée filterTags qui est aussi un int []

Disons que ma variable de balises filtrées ressemble à ceci:

 int[] filteredTags = new int[]{1, 3};

Je souhaite filtrer ma liste ( projets ) pour ne renvoyer que les projets comportant TOUTES les balises répertoriées dans le filtre (dans ce cas, balise au moins 1 ET balise 3 dans la propriété Balises ).

J'essayais d'utiliser Where () et contient () mais cela ne semble fonctionner que si je compare à une valeur unique. Comment pourrais-je faire cela pour comparer une liste avec une autre liste où j'ai besoin d'une correspondance pour tous les éléments de la liste filtrée?

33
leora

EDIT: mieux encore, faites-le comme ça:

var filteredProjects = 
    projects.Where(p => filteredTags.All(tag => p.Tags.Contains(tag)));

EDIT2: Honnêtement, je ne sais pas lequel est le meilleur. Si les performances ne sont pas critiques, choisissez celui que vous pensez le plus lisible. Si c'est le cas, vous devrez le comparer d'une manière ou d'une autre.


Intersect est probablement le chemin à parcourir:

void Main()
{
    var projects = new List<Project>();
    projects.Add(new Project { Name = "Project1", Tags = new int[] { 2, 5, 3, 1 } });
    projects.Add(new Project { Name = "Project2", Tags = new int[] { 1, 4, 7 } });
    projects.Add(new Project { Name = "Project3", Tags = new int[] { 1, 7, 12, 3 } });

    var filteredTags = new int []{ 1, 3 };
    var filteredProjects = projects.Where(p => p.Tags.Intersect(filteredTags).Count() == filteredTags.Length);  
}


class Project {
    public string Name;
    public int[] Tags;
}

Bien que cela semble un peu moche au début. Vous pouvez d’abord appliquer Distinct à filteredTags si vous n’êtes pas sûr qu’ils sont tous uniques dans la liste, sinon la comparaison des nombres ne fonctionnera pas comme prévu.

39
Dyppl

Nous devrions avoir les projets qui incluent (au moins) toutes les balises filtrées, ou d'une manière différente, excluent ceux qui n'incluent pas toutes les balises filtrées ... Nous pouvons donc utiliser Linq Except pour obtenir les balises ne sont pas inclus. Ensuite, nous pouvons utiliser Count() == 0 pour n’avoir que ceux qui n’excluent aucun tag:

var res = projects.Where(p => filteredTags.Except(p.Tags).Count() == 0);

Ou nous pouvons le rendre légèrement plus rapide en remplaçant Count() == 0 par !Any():

var res = projects.Where(p => !filteredTags.Except(p.Tags).Any());
3
Mariano Desanze
var result = projects.Where(p => filtedTags.All(t => p.Tags.Contains(t)));
2
Danny Chen
var filtered = projects;
foreach (var tag in filteredTags) {
  filtered = filtered.Where(p => p.Tags.Contains(tag))
}

La bonne chose avec cette approche est que vous pouvez affiner les résultats de la recherche de manière incrémentielle.

1
Joh

Basé sur http://code.msdn.Microsoft.com/101-LINQ-Samples-3fb9811b ,

EqualAll est l'approche qui répond le mieux à vos besoins.

public void Linq96() 
{ 
    var wordsA = new string[] { "cherry", "Apple", "blueberry" }; 
    var wordsB = new string[] { "cherry", "Apple", "blueberry" }; 

    bool match = wordsA.SequenceEqual(wordsB); 

    Console.WriteLine("The sequences match: {0}", match); 
} 
0
user3583337