Using LINQ I have a list of lists, how can I select all the objects that exist in each list?

I have a list of lists:

List<Tuple<string, List<SomeObject>>

      

I want to select all SomeObjects

that exist in all rows of the list above.

Some will only exist in one or two lists, but I want all objects to exist in each separate list and the rest of the objects to be discarded.

I cannot find an elegant solution without a bunch of C # code. Is there a good way?

+3


source to share


4 answers


list.Select (x => x.Item2 as IEnumerable<SomeObject>)
    .Aggregate((x,y)=> x.Intersect(y))
    .ToList();

      

Or, as Jeppe Stig Nielsen suggested (and I think this is much more elegant):



list.Select(x => x.Item2.AsEnumerable())
    .Aggregate(Enumerable.Intersect)
    .ToList();

      

+7


source


As I understand it correctly, you need the intersection of many lists:



var results = source.First().Item2
foreach (var element in source.Skip(1) )
{
    results = results.Intersect(element.Item2)
}

      

+1


source


Strongly inspired by Juan Lopez's beautiful answer, you can define this extension:

static IEnumerable<TSource> IntersectMany<TSource>(this IEnumerable<IEnumerable<TSource>> sources)
{
  return sources.Aggregate(Enumerable.Intersect);
}

      

then this works:

var result = list.Select(x => x.Item2).IntersectMany();

      

This works because it IEnumerable<out T>

is covariant in T

(C # 4, .NET 4.0).

+1


source


Assuming the class overrides Equals

+ GetHashCode

or you have a custom one IEqualityComparer<SomeObject>

, you can use the following query, which uses Enumerable.All

:

var result = list
    .SelectMany(t => t.Item2)   // select all objects
    .Distinct()                 // just an optimization since duplicates are guaranteed
    .Where(obj => list.All(t => t.Item2.Contains(obj))); 

      

Here's my details:

var list = new List<Tuple<string, List<SomeObject>>>();
list.Add(Tuple.Create("a", new List<SomeObject> { new SomeObject { ID = 1 }, new SomeObject { ID = 2 }, new SomeObject { ID = 4 } }));
list.Add(Tuple.Create("b", new List<SomeObject> { new SomeObject { ID = 1 }, new SomeObject { ID = 2 }, new SomeObject { ID = 3 } }));
list.Add(Tuple.Create("c", new List<SomeObject> { new SomeObject { ID = 1 }, new SomeObject { ID = 2 }, new SomeObject { ID = 3 } }));
list.Add(Tuple.Create("d", new List<SomeObject> { new SomeObject { ID = 1 }, new SomeObject { ID = 2 }, new SomeObject { ID = 3 } }));

      

Only tags SomeObjects

with ID = 1 or ID = 2 are found in all lists and that's the result of the query.

-1


source







All Articles