Ray Booysen
Ray Booysen

Reputation: 30041

LINQ - Select correct values from nested collection

Consider the following class hierarchy:

public class Foo
{
 public string Name { get; set; }
 public int Value { get; set; }
}
public class Bar
{
 public string Name { get; set; }
 public IEnumerable<Foo> TheFoo { get; set; }
}

public class Host
{
  public void Go()
  {
    IEnumerable<Bar> allBar = //Build up some large list
    //Get Dictionary<Bar, Foo> with max foo value
  }
}

What I would like to do using Linq2Objects is to get an KeyValuePair where for each Bar in the allBBar collection we select the Foo with the maximum Value property. Can this be done easily in a single LINQ statement?

Upvotes: 0

Views: 1273

Answers (3)

Joe Chung
Joe Chung

Reputation: 12133

Another way using Aggregate instead of OrderBy so that figuring out the max Foo is O(n) instead of O(n log n):

var query = allBar.ToDictionary(
    bar => bar,
    bar => bar.TheFoo.Aggregate(
        null,
        (max, foo) => (max == null || foo.Value > max.Value) ? foo : max));

Upvotes: 1

Doctor Jones
Doctor Jones

Reputation: 21674

just to add to Jon's comment about MaxBy going pear shaped if you have no foos, you could do an OrderByDescending and then use FirstOrDefault to get at the Max element. If the collection is empty it'd just return null instead of going "pear shaped".

var foobars = bars.ToDictionary(bar => bar, 
                                bar => bar.TheFoo.OrderByDescending(foo => foo.Value).FirstOrDefault());

I don't think this wouldn't be as efficient as MaxBy, but it'd be more robust in the case of an empty collection.

Upvotes: 0

Jon Skeet
Jon Skeet

Reputation: 1503899

Sure, although my preferred solution uses MaxBy from MoreLINQ:

var query = allBar.ToDictionary(x => x, // Key
                                x => x.TheFoo.MaxBy(f => f.Value));

Note that this will go pear-shaped if TheFoo is empty for any Bar instance.

Upvotes: 2

Related Questions