linq GroupBy,输出一定数量(.Take(n)),并合并其余

nfzehxib  于 2023-03-15  发布在  其他
关注(0)|答案(1)|浏览(104)

我已经做了一个Linq查询,我正在按调用分组并对持续时间求和,一切都按预期运行。然而问题是,我得到了太多的结果作为输出。分组后,我想得到最多10个顶级结果,并将其余结果合并到“其余”组。有没有一些方法可以使用linq做到这一点?
下面是我当前查询的一个示例:

IEnumerable<DataModel> data = this.Data
    .GroupBy(g => #here is regex match#)
    .Select(s => new DataModel
    {
      CallerNumber = s.Key,
      Duration = TimeSpan.FromTicks(s.Sum(c => c.Duration.Ticks)),
    })
    .Where(w => !string.IsNullOrEmpty(w.CallerNumber))
    .OrderByDescending(o => o.Duration);

我可以在查询的末尾使用.Take(10);,但是如何将所有剩余的部分合并到“剩余”部分?我的意思是我将得到前10条记录,但是在位置11、12、13、14等处还有更多的记录现在没有显示。如何将它们合并并显示为输出列表中的第11项。

IEnumerable<DataModel> data = this.Data
    .GroupBy(g => #here is regex match#)
    .Select(s => new DataModel
    {
      CallerNumber = s.Key,
      Duration = TimeSpan.FromTicks(s.Sum(c => c.Duration.Ticks)),
    })
    .Where(w => !string.IsNullOrEmpty(w.CallerNumber))
    .OrderByDescending(o => o.Duration)
    .Take(10);

编辑:

我的想法是,我有,比方说电话号码:

050321        4:30
045345        2:00
050321        4:00
045345        6:00
076843        1:00
050321        1:00
032345        3:00
043453        2:00
032345        3:00

这是我想要达到的目标(假设我想获得前3名和其余的组合):

050321        9:30
045345        8:00
032345        6:00
Rest          3:00
mrfwxfqh

mrfwxfqh1#

我建议分组 * 两次 *,即

int top = 10;

var data = this
  .Data
  .GroupBy(item => # here is regex match #)
  .Select(group => (key : group.Key, 
                    total : group.Sum(item => item.Duration.Ticks)))
  .OrderByDescending(pair => pair.total)
  .Select((pair, index) => (pair.key, pair.total, index))
  .GroupBy(rec => rec.index < top ? rec.key : "Rest",
           rec => rec.total)
  .Select(group => new DataModel() {
     CallerNumber = group.Key,
     Duration = TimeSpan.FromTicks(group.Sum(item => item))
   });

其思想是 * 降序排序 *,然后 * 分组 * 所有在"Rest"键下具有索引11, 12, ..的项:

int top = 10;

...

.GroupBy(rec => rec.index < top ? rec.key : "Rest",
         rec => rec.total)

如果rec具有足够小的index0..9),则保留其key,否则将其分组在"Rest"``key下。
Fiddle
如果你想删除一个空的key,你可以过滤掉它:

var data = 
  ...
  .GroupBy(item => # here is regex match #)
  .Where(group => !string.IsNullOrEmpty(group)) 
  ...

或者将其放入"Rest"

var data = 
  ...
  .Select(group => (key : group.Key, 
                    total : group.Sum(item => item.Duration.Ticks)))
  .OrderBy(pair => string.IsNullOrEmpty(pair.key) ? 1 : 0)
  .ThenByDescending(pair => pair.total)
  ...

相关问题