it-swarm.com.de

filtern einer Liste mit LINQ

ich habe eine Liste von Projektobjekten:

IEnumerable<Project> projects

eine Projekt Klasse als Eigenschaft namens Tags . das ist ein int []

ich habe eine Variable namens gefilterteTags die auch ein int [] ist. 

Nehmen wir an, meine gefilterten Tags-Variablen sehen folgendermaßen aus:

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

Ich möchte meine Liste filtern ( projects ), um nur Projekte zurückzugeben, bei denen ALLE Tags im Filter aufgeführt sind (in diesem Fall mindestens Tag 1 und Tag 3 in der Eigenschaft Tags ).

Ich habe versucht, Where () und Contains () zu verwenden, aber das scheint nur zu funktionieren, wenn ich mit einem einzelnen Wert vergleiche. Wie würde ich dies tun, um eine Liste mit einer anderen Liste zu vergleichen, bei der ich eine Übereinstimmung aller Elemente in der gefilterten Liste benötige?

33
leora

EDIT: noch besser, mach es so:

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

EDIT2: Ehrlich gesagt, ich weiß nicht, welche besser ist. Wenn die Leistung nicht kritisch ist, sollten Sie diejenige auswählen, die Ihrer Meinung nach besser lesbar ist. Wenn dies der Fall ist, müssen Sie es irgendwie überprüfen.


Wahrscheinlich ist Intersect der Weg zu gehen:

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;
}

Obwohl das zunächst etwas hässlich erscheint. Sie können zuerst Distinct auf filteredTags anwenden, wenn Sie nicht sicher sind, ob sie alle eindeutig in der Liste sind. Andernfalls funktioniert der Zählwertvergleich nicht wie erwartet.

39
Dyppl

Wir sollten die Projekte haben, die (mindestens) alle gefilterten Tags enthalten oder auf andere Weise gesagt, diejenigen ausschließen, die nicht alle diese gefilterten Tags enthalten .. _. Daher können wir Linq Except verwenden, um diese Tags zu erhalten Sind nicht enthalten. Dann können wir Count() == 0 verwenden, um nur diejenigen zu haben, die keine Tags ausgeschlossen haben:

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

Oder wir können es etwas schneller machen, indem wir Count() == 0 durch !Any() ersetzen:

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))
}

Das Schöne an diesem Ansatz ist, dass Sie Suchergebnisse inkrementell verfeinern können.

1
Joh

Basierend auf http://code.msdn.Microsoft.com/101-LINQ-Samples-3fb9811b ,

EqualAll ist der Ansatz, der Ihren Bedürfnissen am besten entspricht.

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