views:

2254

answers:

6

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.

+2  A: 

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.

Cameron MacFarland
A: 

Try the 'Intersect' method.

IEnumerable<A> result = a1.Intersect(a2).Intersect(a3).Intersect(a4);
Charlino
No, that will give the intersection rather than the distinct values in the union of the set. (It's also not using Id.)
Jon Skeet
Oh I see, misread the question. Also, I didn't care about the Id because the question in it's original form didn't require it.
Charlino
+2  A: 

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();
Dennis Palmer
Thanks, works well.
CRice
+2  A: 

This also works:

new[] {a1, a2, a3, a4}.SelectMany(x => x.Select(y => y.Id)).Distinct();
idursun
Since a1, a2, a3 and a4 are different types, there will be no "best type" match for the implicit typed array... Compiler Error CS0826 (http://is.gd/Udlw)
CMS
It was clarified after my answer that a1, a2, a3 and a4 may have different types.
idursun
Yes, just saw the edit...
CMS
+6  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();
CMS
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.
Dennis Palmer
This is a lot more readable than using the sugared syntax in my opinion...
ShdNx
+2  A: 

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