фильтрация списка с помощью LINQ - PullRequest
36 голосов
/ 23 февраля 2011

У меня есть список объектов проекта:

IEnumerable<Project> projects

a Проект класс как свойство, называемое Теги . это int []

У меня есть переменная с именем FilterTags , которая также является int [] .

Допустим, моя переменная отфильтрованных тегов выглядит следующим образом:

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

Я хочу отфильтровать свой список ( projects ), чтобы он возвращал только проекты, в которых ВСЕ теги перечислены в фильтре (в данном случае как минимум тег 1 И тег 3 в тегах собственность).

Я пытался использовать , где () и Содержит (), но это работает, только если я сравниваю одно значение. Как мне сделать это, чтобы сравнить список с другим списком, где мне нужно сопоставить все элементы в фильтрованном списке ??

Ответы [ 6 ]

40 голосов
/ 23 февраля 2011

РЕДАКТИРОВАТЬ: еще лучше, сделайте это так:

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

РЕДАКТИРОВАТЬ2: Честно говоря, я не знаю, какой из них лучше, поэтому, если производительность не критична, выберите тот, который вы считаете болееудобочитаемый.Если это так, вам придется как-то его тестировать.


Вероятно, Intersect - это путь:

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

Хотя на первый взгляд это кажется немного уродливым.Сначала вы можете применить Distinct к filteredTags, если вы не уверены, являются ли все они уникальными в списке, иначе сравнение подсчетов не будет работать должным образом.

3 голосов
/ 23 февраля 2011

У нас должны быть проекты, которые включают (как минимум) все отфильтрованные теги или, иначе говоря, исключают те, которые не включают все эти отфильтрованные теги. Таким образом, мы можем использовать Linq Except, чтобы получить те теги, которые не включены. Тогда мы можем использовать Count() == 0, чтобы иметь только те, в которых не было тегов:

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

Или мы можем сделать это немного быстрее, заменив Count() == 0 на !Any():

var res = projects.Where(p => !filteredTags.Except(p.Tags).Any());
2 голосов
/ 23 февраля 2011
var result = projects.Where(p => filtedTags.All(t => p.Tags.Contains(t)));
1 голос
/ 23 февраля 2011
var filtered = projects;
foreach (var tag in filteredTags) {
  filtered = filtered.Where(p => p.Tags.Contains(tag))
}

С этим подходом приятно то, что вы можете постепенно улучшать результаты поиска.

0 голосов
/ 03 января 2018

Попробуйте это:

var filteredProjects = 
projects.Where(p => filteredTags.All(tag => p.Tags.Contains(tag)));
0 голосов
/ 29 апреля 2014

На основании http://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b,

EqualAll - это подход, который наилучшим образом соответствует вашим потребностям.

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