五分钟分组

时间:2019-10-17 07:39:14

标签: c# .net linq lambda

我有以下代码

TimeSpan[] hours = new[] { 
  new TimeSpan(10,35,50), 
  new TimeSpan(10,36,48), 
  new TimeSpan(10,41,48), 
  new TimeSpan(10,47,58), 
  new TimeSpan(10,49,14), 
  new TimeSpan(11,22,15), 
  new TimeSpan(11,24,18), 
  new TimeSpan(11,25,25), 
};

我想将小时和分钟按5分钟分组。 我想得到下面的结果

第一小组

**10:35:50
10:36:48
10:41:48** 

第二组

**10:47:58
10:49:14** 

第三小组

**11:22:15
11:24:18
11:25:25**

我尝试了以下代码,但无法获得所需的确切结果

  var query = (from x in hours select x)
    .GroupBy(r=> r.Ticks / TimeSpan.FromMinutes(5).Ticks));

4 个答案:

答案 0 :(得分:0)

您可以尝试实现一个简单的 loop 而不是 Linq

代码:

private static IEnumerable<TimeSpan[]> MyGrouping(IEnumerable<TimeSpan> source, 
                                                  double minutes) {
  List<TimeSpan> list = new List<TimeSpan>();

  foreach (TimeSpan item in source.OrderBy(x => x)) {
    // shall we start a new group?
    if (list.Any() && (item - list.Last()).TotalMinutes > minutes) {
      // if yes, return the previous 
      yield return list.ToArray();

      list.Clear();
    }

    list.Add(item);
  }

  if (list.Any())
    yield return list.ToArray();
}

演示:

var result = MyGrouping(hours, 5)
  .Select((list, index) => $"Group {index + 1}: [{string.Join(", ", list)}]");

Console.Write(string.Join(Environment.NewLine, result));

结果:

Group 1: [10:35:50, 10:36:48, 10:41:48]
Group 2: [10:47:58, 10:49:14]
Group 3: [11:22:15, 11:24:18, 11:25:25]

答案 1 :(得分:0)

您可以通过使用Aggregate确定每个时间段属于哪个“组”,然后GroupBy来确定该组。

TimeSpan[] hours = new[] { 
        new TimeSpan(10,35,50), 
        new TimeSpan(10,36,48), 
        new TimeSpan(10,41,48), 
        new TimeSpan(10,47,58), 
        new TimeSpan(10,49,14), 
        new TimeSpan(11,22,15), 
        new TimeSpan(11,24,18), 
        new TimeSpan(11,25,25), 
    };
    var query = hours.Aggregate(new List<(int group, TimeSpan ts)>(),  (acc,curr) => {
        if(acc.Count == 0)
            acc.Add((0,curr));          
        else 
        {
            var (lastGroup,lastTs) = acc.Last();
            if(curr.Subtract(lastTs).TotalMinutes <= 5)
                acc.Add((lastGroup,curr));
            else
                acc.Add((lastGroup+1,curr));
        }
        return acc;
    }).GroupBy(x => x.group, y => y.ts);
    foreach(var item in query)
        Console.WriteLine(String.Join(", ", item));

输出为

  

10:35:50,10:36:48,10:41:48
  10:47:58,10:49:14
  11:22:15,11:24:18,11:25:25

实时示例:https://dotnetfiddle.net/zXhw0g

Aggregate explained上的一个很好的问题,可以帮助您理解。

答案 2 :(得分:0)

您可以编写一种将项目分组的方法,如下所示:

public static IEnumerable<List<TimeSpan>> GroupItemsWithin(IEnumerable<TimeSpan> times, TimeSpan maxDelta)
{
    var previous = TimeSpan.MinValue;
    var spans    = new List<TimeSpan>();

    foreach (var span in times)
    {
        if (previous == TimeSpan.MinValue || (span - previous) <= maxDelta)
        {
            spans.Add(span);
        }
        else if (spans.Count > 0)
        {
            yield return spans;
            spans = new List<TimeSpan>{ span };
        }

        previous = span;
    }

    if (spans.Count > 0)
        yield return spans;
}

然后您可以像这样使用它:

public static void Main()
{
    TimeSpan[] hours = new[] {
        new TimeSpan(10, 35, 50),
        new TimeSpan(10, 36, 48),
        new TimeSpan(10, 41, 48),
        new TimeSpan(10, 47, 58),
        new TimeSpan(10, 49, 14),
        new TimeSpan(11, 22, 15),
        new TimeSpan(11, 24, 18),
        new TimeSpan(11, 25, 25),
    };

    foreach (var group in GroupItemsWithin(hours, TimeSpan.FromMinutes(5)))
    {
        Console.WriteLine(string.Join(", ", group));
    }
}

输出:

  

10:35:50,10:36:48,10:41:48

     

10:47:58,10:49:14

     

11:22:15,11:24:18,11:25:25

答案 3 :(得分:0)

如果要使用Linq。这是最简单的解决方案Demo

      TimeSpan[] hours = new[] 
      { new TimeSpan(10, 35, 50),
        new TimeSpan(10, 36, 48),
        new TimeSpan(10, 41, 48),
        new TimeSpan(10, 47, 58),
        new TimeSpan(10, 49, 14),
        new TimeSpan(11, 22, 15),
        new TimeSpan(11, 24, 18),
        new TimeSpan(11, 25, 25), };
      int groupID = -1;
      var result = hours.OrderBy(h => h).Select((item, index) =>
        {
          if (index == 0 || (!(Math.Abs(hours[index - 1].Subtract(item).TotalMinutes) <= 5)))
            ++groupID;

          return new { group = groupID, item = item };
        }).GroupBy(item => item.group);