codingjoe
codingjoe

Reputation: 800

C# linq expression in lambda with contains

I am trying to make use of the 'contains' to simulate the old SQL 'where id in (1,2,3,4)' way of filtering a query.

However I have some difficulties in using it where my id's are in a deeper level.

Code:

 public class Category
    {
        public long Id { get; set; }
        public string Name { get; set; }
    }

    public class Characteristica
    {
        public Category Category { get; set; }
        public int Id { get; set; }
        public string Value { get; set; }
    }

    public class Person
    {
        public string Name { get; set; }
        public List<Characteristica> Appearance { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var persons = new List<Person>
            {
                new Person { Name = "Person A", Appearance = new List<Characteristica> { new Characteristica { Id = 22 }, new Characteristica { Id = 5 }, new Characteristica { Id = 12 } }},
                new Person { Name = "Person B", Appearance = new List<Characteristica> { new Characteristica { Id = 1 }, new Characteristica { Id = 6 }, new Characteristica { Id = 11 } }},
                new Person { Name = "Person C", Appearance = new List<Characteristica> { new Characteristica { Id = 2 }, new Characteristica { Id = 8 }, new Characteristica { Id = 13 } }},
                new Person { Name = "Person D", Appearance = new List<Characteristica> { new Characteristica { Id = 2 }, new Characteristica { Id = 5 }, new Characteristica { Id = 10 } }},
                new Person { Name = "Person E", Appearance = new List<Characteristica> { new Characteristica { Id = 1 }, new Characteristica { Id = 8 }, new Characteristica { Id = 10 } }},
                new Person { Name = "Person F", Appearance = new List<Characteristica> { new Characteristica { Id = 1 }, new Characteristica { Id = 6 }, new Characteristica { Id = 23 } }},
            };

            var listOfSearchedIds = new List<int> { 22, 23 };
            var selected = persons.Select(p => p.Appearance.Where(a => listOfSearchedIds.Contains(a.Id))).ToList();
        }
    }

Now I am trying to get 'Person A' and 'Person F' out from my collection by using the contains feauture. However I cannot see what I am doing wrong here.

Can someone shed some light on what I am doing wrong? I have tried different versions of my lambda and this is the closes I can get, but I am getting all 6 items out from my expression.

Upvotes: 15

Views: 113834

Answers (2)

Markus
Markus

Reputation: 22436

Try the following:

var listOfSearchedIds = new List<int> { 22, 23 };
var selected = persons
        .Where(p => listOfSearchedIds
                        .Intersect(p.Appearance
                             .Select(a => a.Id)).Any()).ToList();

By using Intersect, you compare two lists and return the items that are contained in both of them. Intersect uses a HashSet internally and therefore is a very performant way two find the intersection of two sets. Any() returns true if there is at least one item in the resulting list.

Upvotes: 3

Selman Gen&#231;
Selman Gen&#231;

Reputation: 101681

Your way is correct but you should use Where instead of Select

 var selected = persons.Where(p => p.Appearance
                .Where(a => listOfSearchedIds.Contains(a.Id))
                .Any()).ToList();

And you need to use Any to check whether the returning sequence from p.Appearance.Where contains any element.Or you can use Any directly and make it shorter:

var selected = persons.Where(p => p.Appearance
                .Any(a => listOfSearchedIds.Contains(a.Id))
                .ToList();

Upvotes: 34

Related Questions