Home > Back-end >  C# group list by time interval
C# group list by time interval

Time:01-20

I want to group my data based on a given time interval like 1m, 1h, 1d etc..

 var tables = await query.QueryAsync(flux, "AAE");
            return tables.SelectMany(table =>
                table.Records.Select(record =>
                    new MachineDataModel
                    {
                        result = record.GetValueByKey("result").ToString(),
                        table = int.Parse(record.GetValueByKey("table").ToString()),
                        _start = record.GetValueByKey("_start").ToString(),
                        _stop = record.GetValueByKey("_stop").ToString(),
                        _time = record.GetValueByKey("_time").ToString(),
                        _value = int.Parse(record.GetValueByKey("_value").ToString()),
                        _field = record.GetValueByKey("_field").ToString(),
                        _measurement = record.GetValueByKey("_measurement").ToString(),
                        end_time_str = record.GetValueByKey("end_time_str").ToString(),
                        machine = record.GetValueByKey("machine").ToString(),
                        start_time_str = record.GetValueByKey("start_time_str").ToString(),
                    }));
        });

        returnModel.MachineList = results.ToList();

I want to group the data that is in the returnModel.MachineList by a given interval. I have no idea how to do this.

CodePudding user response:

Since you haven't provided the data model, I assumed...

class MachineDataModel
{
    public DateTime _start; //can also be parsed from '_start_time_str'
    public DateTime _end; //can also be parsed from '_end_time_str'
    //..some more....
}

You can Group Elements by a minute interval with:

var GroupByMinutesList = list.GroupBy(x => (x._end - x._start).Minutes);
//replace 'Minutes' with 'Hours', 'Days', etc...

To convert it to a dictionary simply:

var GroupedByMinutesDictionary = GroupByMinutesList.ToDictionary(x => x.Key.ToString()   " minute(s)", x => x.ToList());

the above dictionary will give you:

{
   "1 minute(s)": 
   {
      myMachineDataModel object
   },
   "2 minute(s)":
   {
     myMachineDataModel object
   }
   etc...
}

The Test Data I used

List<MachineDataModel> list = new()
{
    new MachineDataModel
    {
        _start = DateTime.Now,
        _end = DateTime.Now.AddSeconds(30)
    },
    new MachineDataModel
    {
        _start = DateTime.Now,
        _end = DateTime.Now.AddSeconds(90)
    },
    new MachineDataModel
    {
        _start = DateTime.Now,
        _end = DateTime.Now.AddSeconds(45)
    },
    new MachineDataModel
    {
        _start = DateTime.Now,
        _end = DateTime.Now.AddSeconds(75)
    }
};

Result:

//JsonConvert.SerializeObject(GroupedByMinutesDictionary)
{
  "0 minute(s)": [
    {
      "_start": "2022-01-19T10:47:03.2527701 05:00",
      "_end": "2022-01-19T10:47:33.2527733 05:00"
    },
    {
      "_start": "2022-01-19T10:47:03.2528154 05:00",
      "_end": "2022-01-19T10:47:48.2528156 05:00"
    }
  ],
  "1 minute(s)": [
    {
      "_start": "2022-01-19T10:47:03.2528141 05:00",
      "_end": "2022-01-19T10:48:33.2528145 05:00"
    },
    {
      "_start": "2022-01-19T10:47:03.2528158 05:00",
      "_end": "2022-01-19T10:48:18.252816 05:00"
    }
  ]
}

CodePudding user response:

Assuming you can parse your _time string to a DateTime, you can use GroupBy like so:

Func<DateTime, long> GetIntervalKeyGenerator(Interval interval)
    => interval switch
    {
        Interval.Years => date => date.Year,
        Interval.Days => date => date.Year * 1000   date.DayOfYear,  
        ...
        _ => throw new NotImplementedException()
    };

Enumerable.Range(1, 1000)
    .Select(i => DateTime.Now   TimeSpan.FromMinutes(i))
    .GroupBy(GetIntervalKeyGenerator(Interval.Hours), date => date);
  •  Tags:  
  • Related