Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

filtering a list using LINQ

i have a list of project objects:

IEnumerable<Project> projects

a Project class as a property called Tags. this is a int[]

i have a variable called filteredTags which is also a int[].

So lets say my filtered tags variable looks like this:

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

I want to filter my list (projects) to only return projects that have ALL of the tags listed in the filter (in this case at least tag 1 AND tag 3 in the Tags property).

I was trying to use Where() and Contains() but that only seems to work if i am comparing against a single value. How would i do this to compare a list against another list where i need a match on all the items in the filtered list ??

like image 807
leora Avatar asked Feb 23 '11 11:02

leora


People also ask

How to filter list in LINQ?

The next example filters a list with LINQ's Where method. var vals = new List<int> {-1, -3, 0, 1, 3, 2, 9, -4}; List<int> filtered = vals. Where(x => x > 0). ToList(); Console.

How to filter a list based on condition in c#?

Show activity on this post. public Class Car { public string Name {get;set;} public string Color {get;set;} } Car1 = new {"Ford", "White"} Car2 = new {"Ford Fiesta", "Blue"} Car3 = new {"Honda City", "Yellow"} Car4 = new {"Honda", "White"} var carObj = new List<Car>(); carObj. Add(Car1); carObj. Add(Car2); carObj.

How to do filter in c#?

If you're using C# 3.0 you can use linq, which is way better and way more elegant: 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.


2 Answers

EDIT: better yet, do it like that:

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

EDIT2: Honestly, I don't know which one is better, so if performance is not critical, choose the one you think is more readable. If it is, you'll have to benchmark it somehow.


Probably Intersect is the way to go:

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

Although that seems a little ugly at first. You may first apply Distinct to filteredTags if you aren't sure whether they are all unique in the list, otherwise the counts comparison won't work as expected.

like image 86
Dyppl Avatar answered Oct 18 '22 03:10

Dyppl


We should have the projects which include (at least) all the filtered tags, or said in a different way, exclude the ones which doesn't include all those filtered tags. So we can use Linq Except to get those tags which are not included. Then we can use Count() == 0 to have only those which excluded no tags:

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

Or we can make it slightly faster with by replacing Count() == 0 with !Any():

var res = projects.Where(p => !filteredTags.Except(p.Tags).Any());
like image 4
Mariano Desanze Avatar answered Oct 18 '22 02:10

Mariano Desanze