LINQ selecting distinct from 4 IEnumerable lists

11,216

Solution 1

Are they really all lists of the same type? Or do you have

List<A> a1 = new List<A>();
List<B> a2 = new List<B>();
List<C> a3 = new List<C>();
List<D> a4 = new List<D>();

and you want to combine those because all 4 types have a common string Id property?

OK, your edit shows I was on the right track. You need an Interface that defines the string Id property and each type A, B, C and D need to implement that Interface.

Then each list will be of the Interface type and the concat answers will work.

If you don't have ability to define the interface, then you could use LINQ to query each list for only the Id field (you should get IQueryable<String> results) and then concat those results.

Edit: Here's a LINQ query that should give you what you're looking for:

var uniqueIds = (from a in a1
                 select a.Id).Concat(
                 from b in a2
                 select b.Id).Concat(
                 from c in a3
                 select c.Id).Concat(
                 from d in a4
                 select d.Id).Distinct();

Solution 2

Since they are different types, I would select first the Id property to get an IEnumerable<string>, and then concatenate the results:

var query = a1.Select(a=> a.Id)
              .Concat(a2.Select(b=> b.Id))
              .Concat(a3.Select(c=> c.Id))
              .Concat(a4.Select(d=> d.Id))
              .Distinct();

Solution 3

Union

Of course, you can simplify this:

var uniqueIds = (from a in a1
                 select a.Id).Concat(
                 from b in a2
                 select b.Id).Concat(
                 from c in a3
                 select c.Id).Concat(
                 from d in a4
                 select d.Id).Distinct();

By using Union (which does an implicit 'Distinct'), to become:

var uniqueIds =  (from a in a1
                 select a.Id).Union(
                 from b in a2
                 select b.Id).Union(
                 from c in a3
                 select c.Id).Union(
                 from d in a4
                 select d.Id);

Solution 4

This also works:

new[] {a1, a2, a3, a4}.SelectMany(x => x.Select(y => y.Id)).Distinct();

Solution 5

You can concat IEnumerables of the same type, and then select the item you need.

var query = a1
    .Concat(a2)
    .Concat(a3)
    .Concat(a4)
    .Select(a => a.ID)
    .Distinct();

EDIT: Based on the new question... Selecting from different list types isn't possible in a single query. The best way to do that would be to have a common type that includes the property you're selecting and then run the above query with the base type.

Share:
11,216
CRice
Author by

CRice

Updated on June 13, 2022

Comments

  • CRice
    CRice almost 2 years

    Imagine four lists, all at least have this Id string property, but may have other properties:

    public class A //or B, C, D
    {
        public string Id { get; set; }
        //..other properties
    }
    
    //so:  
    List<A> a1 = new List<A>();
    List<B> a2 = new List<B>();
    List<C> a3 = new List<C>();
    List<D> a4 = new List<D>();
    

    I want to select all DISTINCT ids in: a1, combined with a2, a3 and a4

    I thought LINQ syntax would be ideal but how do you combine these to an IEnumerable result with a single string property, for example something with a definition of class A.

  • Christian C. Salvadó
    Christian C. Salvadó almost 15 years
    Since a1, a2, a3 and a4 are different types, there will be no "best type" match for the implicit typed array... Compiler Error CS0826 (is.gd/Udlw)
  • CoderDennis
    CoderDennis almost 15 years
    Exactly the same result as what I finally came up with. The first version of the question didn't make it perfectly clear that they were different types.
  • idursun
    idursun almost 15 years
    It was clarified after my answer that a1, a2, a3 and a4 may have different types.