iLemming
iLemming

Reputation: 36166

Linq, get distinct elements grouped by a field

I feel stupid, but I have to admit, I need your help guys in seemingly easy to find the right answer situation

 public class Foo
 {
     public string Name { get; set; }
     public string Time { get; set; }

     public Foo(string name, string time)
     {
        Name = name;
        Time = time;
     }
 }

var o = new List<Foo>
                  {
                      new Foo("Breakfast","9:00"),
                      new Foo("Lunch", "12:00"),
                      new Foo("Breakfast", "8:00")
                  };

How to get only Breakfast at 9:00 and Lunch, and not include Breakfast at 8?

I started like that:

var a = o.GroupBy(x => x.Name);

But it will give you only Name, where I need Time too.

Upvotes: 2

Views: 538

Answers (3)

Reb.Cabin
Reb.Cabin

Reputation: 5567

Why not something like the following? (I also took the liberty of making your code a bit smaller -- I think since your properties are public, you don't need a constructor, but can just use object-initializer syntax instead. This should all run in LinqPad:

void Main() {
    var os = new [] {
        new Foo{Name="Breakfast",Time="9:00"},
        new Foo{Name="Lunch", Time="12:00"},
        new Foo{Name="Breakfast", Time="8:00"}
    };

    os.Where(o => DateTime.Parse(o.Time).Hour > 8).Dump();
}

public class Foo
{
    public string Name { get; set; }
    public string Time { get; set; }
}

Upvotes: 0

Jon Skeet
Jon Skeet

Reputation: 1499810

One option is:

var a = o.GroupBy(x => x.Name)
         .Select(g => g.First());

Or you could use DistinctBy from MoreLINQ:

var a = o.DistinctBy(x => x.Name);

The latter is more efficient in memory, and will start yielding results immediately, whereas the first approach has to read all the data before it can return anything. On the other hand, the latter requires MoreLINQ (or copying the code).

EDIT: Here I'm assuming LINQ to Objects (as MoreLINQ certainly won't work with other providers) and that you're happy with the first occurrence for any group being representative of that group.

Upvotes: 3

driis
driis

Reputation: 164281

var a = o.GroupBy(x => x.Name).Select(g => g.First())

But think about that .First() call. How do you want to select the correct element when there is more than one - you might want to sort the elements to get the latest / earliest, or whatever your requirement is.

Upvotes: 5

Related Questions