How to arrange items in a group by linq query and select the first?

I have a dataset that contains type, date and value.

I want to group by type, and for each set of values ​​in each group I want to choose the one with the newest date.

Here is the code that works and gives the correct result, but I want to do all this in a single linq query, not in an iteration. Any ideas how I can achieve the same result as this, using an exclusively linq query ...?

using System;
using System.Linq;
using System.Collections.Generic;

public class Program {

    public static void Main() {

        var mydata = new List<Item> {
            new Item { Type = "A", Date = DateTime.Parse("2016/08/11"), Value = 1 },
            new Item { Type = "A", Date = DateTime.Parse("2016/08/12"), Value = 2 },
            new Item { Type = "B", Date = DateTime.Parse("2016/08/20"), Value = 3 },
            new Item { Type = "A", Date = DateTime.Parse("2016/08/09"), Value = 4 },
            new Item { Type = "A", Date = DateTime.Parse("2016/08/08"), Value = 5 },
            new Item { Type = "C", Date = DateTime.Parse("2016/08/17"), Value = 6 },
            new Item { Type = "B", Date = DateTime.Parse("2016/08/30"), Value = 7 },
            new Item { Type = "B", Date = DateTime.Parse("2016/08/18"), Value = 8 },
        };

        var data = mydata.GroupBy(_ => _.Type);

        foreach (var thing in data) {

            #region 

            // How can I remove this section and make it part of the group by query above... ?          
            var subset = thing.OrderByDescending(_ => _.Date);
            var top = subset.First();

            #endregion

            Console.WriteLine($"{thing.Key} {top.Date.ToString("yyyy-MM-dd")} {top.Value}");

        }           
    }

    public class Item {

        public string Type {get;set;}
        public DateTime Date {get;set;}
        public int Value {get;set;}

    }   
}

// Output:
//   A 2016-08-12 2
//   B 2016-08-30 7
//   C 2016-08-17 6
+4
source share
4 answers

Use selectto get FirstOrDefault(or First- due to grouping you will not get zero), sorted in descending order:

var data = mydata.GroupBy(item => item.Type)
                 .Select(group => group.OrderByDescending(x => x.Date)
                 .FirstOrDefault())
                 .ToList();

Or SelectManyalong withTake(1)

var data = mydata.GroupBy(item => item.Type)
                 .SelectMany(group => group.OrderByDescending(x => x.Date)
                 .Take(1))
                 .ToList();
+7

Select :

var topItems = mydata.GroupBy(item => item.Type)
                     .Select(group => group.OrderByDescending(item => item.Date).First())
                     .ToList();

topItems List<Item>, Type.


Dictionary<string,Item> Type Item Type:

var topItems = mydata.GroupBy(item => item.Type)
                     .ToDictionary(group => group.Key,
                              group => group.OrderByDescending(item => item.Date).First());
+2
var data = mydata.GroupBy(
    item => item.Type,
    (type, items) => items.OrderByDescending(item => item.Date).First());

foreach (var item in data)
{
    Console.WriteLine($"{item.Type} {item.Date.ToString("yyyy-MM-dd")} {item.Value}");
}
+2
source

Group by type for each group, order by date in descending order and select the first (newest).

mydata.GroupBy(i => i.Type).Select(g => g.OrderByDescending(i => i.Date).First());
+1
source

Source: https://habr.com/ru/post/1650926/