views:

684

answers:

3

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?

+2  A: 

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.

Jon Skeet
And without the MaxBy option?
Ray Booysen
Then you'd basically want to write your own implementation of MaxBy :) You *could* do something horrible, but it would be a lot neater just to include MaxBy in your code.
Jon Skeet
Fair enough. ;)
Ray Booysen
A: 

Hi, 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.

DoctaJonez
+1  A: 

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