选择组属性最大值的结果



这是我的代码:

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

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

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;

您可以使用聚合:

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

在我看来,你正在做的事情很好,因为你可以在相同的最高收入下拥有超过一个小时。话虽如此,您可以随时使用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的聚合类型。

如果你真的想要一个带有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}");
}

最新更新