3

I have two List objects, listA and listB, which contain a collection of User objects.

Each User object has a property ID.

I want to get a list of users which are present in both listA and listB based on their ID property.

Here is my code so far:

listA.Where(a => listB.Any(b => b.ID == a.ID));

Is there a better way to do this? It feels like it could be inefficient, especially if listB is large.

The User object does not implement IEquatable.

James Monger
  • 10,181
  • 7
  • 62
  • 98
  • 1
    Are the IDs unique? Could maybe use a HashSet instead with the ID as the key. – Equalsk Dec 21 '16 at 13:27
  • The IDs are unique `Guid` objects. If two `User` objects have the same `ID` then they are the same (but not directly equatable). – James Monger Dec 21 '16 at 13:28
  • Then create two HashSets with the IDs as the key, use the method you've shown but compare the keys. Or as other people have pointed out `Intersect()` might be better. Haven't tested this hence a comment only. – Equalsk Dec 21 '16 at 13:29
  • The library that I am using gives me the users as `List` objects so I think manually converting them to `HashSet` objects would negate any performance improvements, surely? – James Monger Dec 21 '16 at 13:30
  • What is it with the upvotes today? _"Ooh cool, I would like to know this too"_ does not make something a good question. This question has been asked plenty of times before. See also [C# Linq intersect/except with one part of object](http://stackoverflow.com/questions/10633375/c-sharp-linq-intersect-except-with-one-part-of-object). – CodeCaster Dec 21 '16 at 13:31
  • Oh, that's probably true. Wasn't aware you were limited to lists. I'll tap out then. – Equalsk Dec 21 '16 at 13:32
  • 1
    @CodeCaster my object does not implement `IEquatable`. This is not a duplicate of your linked question. – James Monger Dec 21 '16 at 13:33
  • 1
    Then you create a new `IEqualityComparer` and pass that to `Intersect()`. That variant of the same question has been asked enough times as well. See also [Using LINQ to objects Intersect and Except on a specific property](http://stackoverflow.com/questions/3998232/using-linq-to-objects-intersect-and-except-on-a-specific-property), – CodeCaster Dec 21 '16 at 13:33
  • Maybe I'm going blind @CodeCaster, I can't see where that linked answer explains about creating an `IEqualityComparer` and passing it into `Intersect`. – James Monger Dec 21 '16 at 13:39
  • [The first one I linked to after you said `User` doesn't implement `IEquatable`](http://stackoverflow.com/questions/10633375/c-sharp-linq-intersect-except-with-one-part-of-object). Look; you can try and spend your effort in battling my duplicate close vote which I'm not going to retract, because this question is not unique, and plenty of questions deal with this very subject. I'd advise you to read those questions instead. I'm not here to fight you; I'm here to fight duplication. – CodeCaster Dec 21 '16 at 13:50

3 Answers3

2

If User implements IEquatable<User>, assumption is that two User are the same if ID are the same, then you can use LINQ Intersect. For example:

listA.Intersect(listB);

If User does not implement IEquatable<User> you can invoke Intersect with IEqualityComparer<User>. For Example:

listA.Intersect(listB, new UserEqualityComparer());

where

UserEqualityComparer : IEquatable<User> {...}
Johnny
  • 8,939
  • 2
  • 28
  • 33
1

This should do it:

var result = listA.Intersect(listB);

Assuming that your User class implements the IEquatable<User>

if this is not your case, then you can do something like that n order to intersect both lists based on the ID value:

var result = listA.Select(s1 => s1.ID).ToList().Intersect(listB.Select(s2 => s2.ID).ToList()).ToList();

This is creating two new lists of the ID values in both lists, and get the intersection between them.

Mohammed Swillam
  • 9,119
  • 4
  • 36
  • 47
1

Another option is to Join on Id property of both collections..

var results = listA.Join(listB, a => a.Id, b=> b.Id, (a, b) => a);
Milen
  • 8,697
  • 7
  • 43
  • 57