15

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.

3
  • What does happen? do you get an error? Do you get the wrong information? I had assumed you were running against a database but your example does not look like you are. Can you put it on complify.net? Commented Feb 20, 2014 at 21:19
  • In line with the answer from Markus maybe use a HashSet rather than a List for Characteristica. Commented Feb 20, 2014 at 21:39
  • No, I did not get an error. I was just expecting to get a list of the person that I need. My example is with objects, but in real code I am retrieving data from a database using EF 5. Commented Feb 20, 2014 at 22:23

2 Answers 2

34

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();
Sign up to request clarification or add additional context in comments.

1 Comment

I tested both methods in LINQPad 5 and they both yielded the same SQL in the end. DECLARE p0 Int = 2 DECLARE p1 Int = 3 SELECT [t0].[Id], [t0].[Name], [t0].[Description], [t0].[ModifiedBy], [t0].[ModifiedDate], [t0].[CreatedBy], [t0].[CreatedDate], [t0].[RowVersion], [t0].[TriggerTypeGuid] FROM [TriggerType] AS [t0] WHERE EXISTS(SELECT NULL AS [EMPTY] FROM [TriggerClass] AS [t1] WHERE ([t1].[TriggerTypeId] IN (p0, p1)) AND ([t1].[TriggerTypeId] = [t0].[Id])) So Selman is correct in pointing out that either method works but the second one is shorter, but maybe less explicit.
3

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.

1 Comment

Intersect will work with LINQ to objects, but if you want this against a database (EF/L2S), you need to go with Contains.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.