【问题标题】:C# Linq double groupby need min/max for hourly values once per dayC# Linq double groupby 需要每天一次的每小时值的最小值/最大值
【发布时间】:2015-05-15 13:37:58
【问题描述】:

我已经玩了一段时间了,但不能完全得到我想要的结果。

我有一个这样的对象:

public class Point
{
    public string Tag {get;set;}
    public DateTime Time {get;set;}
    public int Value {get;set;}
}

每个标签每天将有 24 个值(每小时一个)。数据将如下所示(标签/时间/值):

x / 5-15-2015 - 0100 / 10 
x / 5-15-2015 - 0200 / 20 
x / 5-15-2015 - 0300 / 30 
y / 5-15-2015 - 0100 / 20 
y / 5-15-2015 - 0200 / 30 
x / 5-16-2015 - 0100 / 10 

例如...

我想按标签和日期排序,然后获取每天 24 小时的最小/最大/平均值。目标是创建以下对象。

Public class NewPoint
{
    public string Tag {get;set;}
    public DateTime Date {get;set;}
    public int LowValue {get;set;}
    public int HighValue {get;set;}
    public int AvgValue {get;set;}
}

结果对象的位置(标签/日期/LowValue/HighValue/AvgValue):

x / 5-15-2015 / 10 / 30 / 20 
y / 5-15-2015 / 20 / 30 / 25 
x / 5-16-2015 / 10 / 10 / 10 

我遇到了以下问题:

group list by new {list.Tag, list.Time.ToString("d") } into dateGroup

我还认为我需要两个 linq 语句。一个按标签和日期分组以查找每个标签/日期的最小/最大/平均值,另一个用于获取日期 [0](或每个标签的不同日期)以及最小/最大/平均传递给新点对象。

欢迎提出建议,谢谢!

【问题讨论】:

    标签: c# linq date


    【解决方案1】:

    根本不需要两个语句...也不使用字符串转换。只需使用每个组的密钥,以及DateTime.Date 属性:

    var query = list.GroupBy(x => new { x.Tag, x.Time.Date })
                    .Select(g => new NewPoint
                            {
                                Tag = g.Key.Tag,
                                Date = g.Key.Date,
                                LowValue = g.Min(x => x.Value),
                                HighValue = g.Max(x => x.Value),
                                AvgValue = (int) g.Average(x => x.Value)
                            });
    

    AvgValue 的强制转换是必需的,因为 Average 的返回类型是 double - 您可能需要考虑更改您的属性类型。

    【讨论】:

    • 据我所知,他的日期可能有不同的时间,这就是为什么他在没有时间的情况下转换为字符串
    • @RodrigoLópez:这就是我使用Date 属性的原因——同样,这里不需要进行字符串转换。 (作为一般规则,除非您的目标是实际上生成文本,否则不要使用字符串转换。几乎总是有更好的方法。)
    • 太棒了!正是我正在寻找的,谢谢乔恩。
    • 还有一个问题。实际上,我在 NewPoint 对象中还有一些属性,我正在做一些 if 检查,并调用一些辅助方法来计算。我可以将这些 if 检查添加到 .select 语句的末尾,还是必须再次遍历所有新对象? .select 中的任何内容似乎都是纯映射(attr = blah)
    • @Shak3nNotStur3d:如果您还有其他问题,请在新帖子中提出。
    【解决方案2】:

    这样的事情就是你所追求的:

        public class Point
        {
            public string Tag { get; set; }
            public DateTime Time { get; set; }
            public int Value { get; set; }
        }
    
        public class NewPoint
        {
            public string Tag {get;set;}
            public DateTime Date {get;set;}
            public int LowValue {get;set;}
            public int HighValue {get;set;}
            public double AvgValue {get;set;}
        }
    
        public List<NewPoint> Summary(List<Point> list)
        {
            return list
                .GroupBy(p => new {p.Tag, p.Time.Date})
                .Select(grp => new NewPoint()
                {
                    Tag = grp.Key.Tag,
                    Date = grp.Key.Date,
                    LowValue = grp.Min(p => p.Value),
                    HighValue = grp.Max(p => p.Value),
                    AvgValue = grp.Average(p => p.Value),                
                })
                .ToList();
        }
    

    注意平均值是双倍的,因此更新 NewPoint 以反映这一点。

    【讨论】:

    • Drat,被 Skeet 抢先!甚至认为我不会是愚蠢的!
    • 感谢吉恩的回复。
    猜你喜欢
    • 2017-10-02
    • 2015-07-04
    • 1970-01-01
    • 1970-01-01
    • 2015-01-09
    • 2019-05-18
    • 2023-04-10
    • 2015-09-12
    • 2017-03-22
    相关资源
    最近更新 更多