选择组属性最大值的结果

时间:2018-09-20 14:11:47

标签: c# linq

那是我的代码:

class Data
{
    public DateTime Date { get; private set; }
    public int Income { get; private set; }
    public Data(DateTime date, int income)
    {
        Date = date;
        Income = income;
    }
}

public static List<Data> GetSampleData()
{
    var now = DateTime.Now.Date;

    return new List<Data>()
    {
        new Data(now.AddMinutes(-15), 15), //23:45
        new Data(now.AddMinutes(-30), 10), //23:30
        new Data(now.AddMinutes(-45), 7), //23:15
        new Data(now.AddMinutes(-55), 8), //23:05
        new Data(now.AddMinutes(-62), 0), //23:58
        new Data(now.AddMinutes(-67), 12), //22:53
        new Data(now.AddMinutes(-70), 1), //22:50
    };
}

我想在哪个小时获得最高的收入。带有示例数据,它应该给我以下结果:

Income: 33
Hour: 23

我所管理的是这个

var data = GetSampleData();

var result = data.GroupBy(x => new
{
    hour = x.Date.Hour
})
.Select(z => new
{
    Sum = z.Sum(a => a.Income),
    Hour = z.Key.hour
})
.OrderByDescending(x => x.Sum)
.FirstOrDefault();

这正在工作。但是由于OrderByDescending,我不喜欢我的解决方案。有没有更好的方法来解决这个问题?如果可能的话,我想使用Max解决方案,但是我无法编写代码。会是:

Get max sum of incomes from groups

4 个答案:

答案 0 :(得分:1)

在较新的.NET版本中,可以使用C# 7.0 tuple types(总和必须是第一个元组项):

var result = data.GroupBy(d => d.Date.Hour)
                 .Max(g => (Sum: g.Sum(d => d.Income), Hour: g.Key));

或作为单独的变量:

(int Sum, int Hour) = data.GroupBy(d => d.Date.Hour)
                          .Max(g => (g.Sum(d => d.Income), g.Key));

在较旧的.NET版本中,System.Tuple<T1,T2>

var result = data.GroupBy(d => d.Date.Hour)
                 .Max(g => Tuple.Create(g.Sum(d => d.Income), g.Key));

如果一个以上的元组具有最大总和,则结果为具有最大小时数的元组。


不带元组的更有效的替代方法可能是对两个值使用相同的数字:

int maxSumHour = data.GroupBy(d => d.Date.Hour)
                     .Max(g => g.Sum(d => d.Income) * 100 + g.Key));

int Sum = maxSumHour / 100, Hour = maxSumHour % 100;

答案 1 :(得分:0)

您可以使用Aggregate:

    .Aggregate( (curMax, x) => (curMax == null) || (x.Sum > curMax.Sum) ? x : curMax );

答案 2 :(得分:0)

在我看来,您的工作还不错,因为您可以在相同的最高收入下拥有一个多小时。话虽如此,您始终可以使用Aggregate

var sums = data.GroupBy(d => d.Date.Hour)
           .Select(g => new { hour = g.Key, sum = g.Sum(d => d.Income) });
var maxData = sums.Aggregate(
              sums.FirstOrDefault(), //First parameter
              (max, next) => next.sum > max.sum ? next : max, //Second parameter
              sum => sum //Third parameter
              ); 

说明:

  1. 第一部分是相同的。您可以按小时分组,然后选择小时和总和。
  2. Aggregate函数使用种子作为第一个参数,在这种情况下,它是总和的第一项。
  3. 下一个表达式是一个用于比较和并递归选取较大的函数的函数。
  4. 最后一个参数选择要返回的结果。

如果您检查maxData,它将使用属性hoursum聚合类型。

答案 3 :(得分:0)

如果您真的想使用Max()解决方案,请不要使用匿名类型,而是先创建一个类/结构并实现IComparable

    public struct IncomePerHour : IComparable<IncomePerHour>
    {
        public int Income { get; set; }
        public int Hour { get; set; }
        public int CompareTo(IncomePerHour other)
        {
            return Income.CompareTo(other.Income); 
        }
    }

然后,不要使用您选择的匿名结果,而是将其设为您刚创建的类/结构。

       var data = GetSampleData();
        var result = data.GroupBy(x => x.Date.Hour)
       .Select(z => new IncomePerHour
       {
           Income = z.Sum(a => a.Income),
           Hour = z.Key
       })
       .Max();

如果您想重复使用数据:

    public class Data : IComparable<Data>
    {
        public DateTime Date { get; private set; }
        public int Income { get; private set; }
        public Data(DateTime date, int income)
        {
            Date = date;
            Income = income;
        }

        public int CompareTo(Data other)
        {
            return Income.CompareTo(other.Income);
        }
    }

    class Program
    {
        var data = GetSampleData();
        var result = data.GroupBy(x => x.Date.Hour)
       .Select(z => new Data (z.First().Date, z.Sum(a => a.Income)))
       .Max();

        Console.WriteLine($"Hour: {result.Date.Hour}, Income:{result.Income}");
    }