简体   繁体   中英

LINQ selecting distinct from 4 IEnumerable lists

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.

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();

这也有效:

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

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

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();

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM