【问题标题】:How can I group by aggregation?如何按聚合分组?
【发布时间】:2019-06-12 12:44:36
【问题描述】:

我有以下数据:

ATMID    StatusId  ComponentId   FromDateTime          ToDateTime
4           1          3        2019-01-01 18:20     2019-01-01 18:45
4           2          5        2019-01-01 18:25     2019-01-01 18:45
5           3          2        2019-01-01 18:10     2019-01-01 18:45 
5           1          2        2019-01-01 18:00     2019-01-01 18:45
5           6          5        2019-01-01 18:46     2019-01-01 18:50

我想以这样的方式聚合它,结果是:

Atmid    St_Comp         FromDateTime          ToDateTime
  4    {(1,3),(2,5)}    2019-01-01 18:20      2019-01-01 18:45 
  5    {(3,2),(1,2)}    2019-01-01 18:00      2019-01-01 18:45 
  5    {(6,5)}          2019-01-01 18:46      2019-01-01 18:50 

如何使用 Linq 实现这一点?

这是我的代码:

var grouped = Problem_Fact_Measure_Overalls.GroupBy(
                  i => new { i.ATMId},
                  i => new {i.ComponentId,i.StatusId},
                  (Atmid, St_Comp) => new { Atmid, St_Comp });

但我无法汇总 FromDateTime 的最小值。

【问题讨论】:

  • 那么,您希望它们以两个(对)为一组吗?
  • 你尝试了什么?
  • 这不仅仅是严格分组,Atmid = 5 有两行。我猜这是因为 fromDate > ToDate 最后一行?请用您已经做出的努力完整地说明您的问题。
  • 为什么是重叠标签?
  • 根据这么少的输入很难获得满足您要求的参数。请更具体地说明您想要实现的目标、您已经尝试过的内容以及具体您遇到的问题。目前它读起来像“请为我做这件事”。

标签: c# linq group-by overlapping


【解决方案1】:

需要像这样使用Aggregate方法:

var result = data
    .Aggregate(
        new List<KeyValuePair<DateTimeRange, List<AtmRecord>>>(),
        (accumulator, atmRecord) => {
            var segment = accumulator.FirstOrDefault(
                v => atmRecord.ATMID == v.Value.First().ATMID && 
                    atmRecord.FromDateTime <= v.Key.To &&
                    atmRecord.ToDateTime >= v.Key.From);

            if (segment.Key == null)
            {
                accumulator.Add(new KeyValuePair<DateTimeRange, List<AtmRecord>>(
                    new DateTimeRange(atmRecord.FromDateTime, atmRecord.ToDateTime),
                    new List<AtmRecord>() {atmRecord}));

                return accumulator; 
            }

            if (atmRecord.FromDateTime < segment.Key.From)
            {
                segment.Key.From = atmRecord.FromDateTime;
            }

            if (atmRecord.ToDateTime > segment.Key.To)
            {
                segment.Key.To = atmRecord.ToDateTime;
            }                        

            segment.Value.Add(atmRecord);

            return accumulator;
        },
        accumulator => {
            return accumulator
                .Select(v => new 
                {
                    Atmid = v.Value.First().ATMID,
                    St_Comp = v.Value
                        .Select(r => (r.StatusId, r.ComponentId))
                        .ToArray(),
                    FromDateTime = v.Key.From,
                    ToDateTime = v.Key.To
                });
        })
        .ToArray();

/* result: 
[0]:{ Atmid = 4, St_Comp = {(int, int)[2]}, FromDateTime = {2019-01-01 6:20:00 p.m.}, ToDateTime = {2019-01-01 6:45:00 p.m.} }
Atmid [int]:4
FromDateTime [DateTime]:{2019-01-01 6:20:00 p.m.}
St_Comp:{(int, int)[2]}
[0]:(1, 3)
[1]:(2, 5)
ToDateTime [DateTime]:{2019-01-01 6:45:00 p.m.}

[1]:{ Atmid = 5, St_Comp = {(int, int)[2]}, FromDateTime = {2019-01-01 6:00:00 p.m.}, ToDateTime = {2019-01-01 6:45:00 p.m.} }
Atmid [int]:5
FromDateTime [DateTime]:{2019-01-01 6:00:00 p.m.}
St_Comp:{(int, int)[2]}
[0]:(3, 2)
[1]:(1, 2)
ToDateTime [DateTime]:{2019-01-01 6:45:00 p.m.}

[2]:{ Atmid = 5, St_Comp = {(int, int)[1]}, FromDateTime = {2019-01-01 6:46:00 p.m.}, ToDateTime = {2019-01-01 6:50:00 p.m.} }
Atmid [int]:5
FromDateTime [DateTime]:{2019-01-01 6:46:00 p.m.}
St_Comp:{(int, int)[1]}
[0]:(6, 5)
ToDateTime [DateTime]:{2019-01-01 6:50:00 p.m.}
 */

测试数据:

var data = new[]{ 
    new AtmRecord( 4, 1, 3, DateTime.Parse("2019-01-01 18:20"), DateTime.Parse("2019-01-01 18:45") ),
    new AtmRecord( 4, 2, 5, DateTime.Parse("2019-01-01 18:25"), DateTime.Parse("2019-01-01 18:45") ),
    new AtmRecord( 5, 3, 2, DateTime.Parse("2019-01-01 18:10"), DateTime.Parse("2019-01-01 18:45") ),
    new AtmRecord( 5, 1, 2, DateTime.Parse("2019-01-01 18:00"), DateTime.Parse("2019-01-01 18:45") ),
    new AtmRecord( 5, 6, 5, DateTime.Parse("2019-01-01 18:46"), DateTime.Parse("2019-01-01 18:50") )
};

附加类:

internal sealed class AtmRecord
{
    public int ATMID { get; }
    public int StatusId { get; }
    public int ComponentId { get; }
    public DateTime FromDateTime { get; }
    public DateTime ToDateTime { get; }

    public AtmRecord(int aTMID, int statusId, int componentId, DateTime fromDateTime, DateTime toDateTime)
    {
        ATMID = aTMID;
        StatusId = statusId;
        ComponentId = componentId;
        FromDateTime = fromDateTime;
        ToDateTime = toDateTime;
    }
}

internal sealed class DateTimeRange
{
    public DateTime From { get; set; }

    public DateTime To { get; set; }

    public DateTimeRange(DateTime from, DateTime to)
    {
        From = from;
        To = to;
    }
}

【讨论】:

    【解决方案2】:

    你想这样分组吗?

    var grouped = Problem_Fact_Measure_Overalls.GroupBy(r => r.ATMID)
    .Select(g => new
    {
        Atmid = g.Key,
        St_Comp = g.Select(r => (r.StatusId, r.ComponentId)).ToArray(),
        FromDateTime = g.Min(r => r.FromDateTime),
        ToDateTime = g.Max(r => r.ToDateTime)
    });
    

    输出:

    4   (1, 3), (2, 5)           2019-01-01 18:20   2019-01-01 18:45
    5   (3, 2), (1, 2), (6, 5)   2019-01-01 18:00   2019-01-01 18:50
    

    【讨论】:

      猜你喜欢
      • 2014-05-29
      • 1970-01-01
      • 1970-01-01
      • 2015-03-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多