选择分组结果

4

我有一个客户列表

public class Client
{
    public string ClientID { get; set; } // Client
    public decimal Amount { get; set; } // Sales $
}

例如,使用以下数据:
ClientID | Amount
---------+-------
000021354|   200
000021353|   300
000021353|   400
000021352|   100
000021351|   200
000021350|   100

代码:

List<Client> cList = new List<Client>();
cList.Add(new Client() { ClientID = "000021354", Amount = 200 });
cList.Add(new Client() { ClientID = "000021353", Amount = 300 });
cList.Add(new Client() { ClientID = "000021353", Amount = 400 });
cList.Add(new Client() { ClientID = "000021352", Amount = 100 });
cList.Add(new Client() { ClientID = "000021351", Amount = 200 });
cList.Add(new Client() { ClientID = "000021350", Amount = 100 });

我希望按照客户ID分组,并对销售额进行求和。选择前3名(销售额最高的客户) - 其余客户应分组为“其他”。
所以结果应该是:
ClientID | Amount
---------+-------
000021353|   700 #1 (300 + 400)
000021354|   200 #2
000021351|   200 #3
others   |   200 // (000021352 + 000021350)

但是我的分组不起作用:
var Grouped = cList.GroupBy(x => x.ClientID)
                .OrderByDescending(x => x.Select( y=> y.Amount).Sum())
                .Select(x => x).Take(3); //how to add "others" ?

你目前是否得到了任何结果? - monstertjie_za
但是我的分组好像不起作用了。你是什么意思?你是否遇到编译器错误?运行时异常?还是出现了意外的结果? - Rik
@Rik - 不期望的结果,我不知道如何添加“其他”。 - Byyo
@Byyo 你说的“前三名”是指什么?第一项结果?最高金额?每个客户的最高金额? - Rik
5个回答

3
我建议使用类似以下的内容。
var grouped = a.GroupBy(x => x.ClientID, y => y.Amount)
               .Select(x => new Client { ClientID = x.Key, Amount = x.Sum() })
               .OrderByDescending(x => x.Amount);

var final = grouped.Take(3).ToList();
final.Add(new Client { ClientID = "Others", Amount = grouped.Skip(3).Sum(x => x.Amount) });

1
var grouped = cList.GroupBy(x => x.ClientID)
                   .Select(g => new { Id = g.Key, TotalAmount = g.Sum(c => c.Amount)})
                   .OrderByDescending(x => x.TotalAmount);

var result = grouped.Take(3).ToList();
result.Add(new {Id = "others", TotalAmount = grouped.Skip(3).Sum(x => x.TotalAmount)});

1
为了完成您需要的操作,我认为您需要先进行分组,然后再创建您期望的结果。
var query=cList.GroupBy(x => x.ClientID)
               .Select(g=>new{UserId=g.Key, Amount=g.Sum(y=>y.Amount)})
               .OrderByDescending(e=>e.Amount);

var result= query.Take(3).Concat(new[]{new {UserId="others", Amount=query.Skip(3).Sum(e=>e.Amount)}});

PS:我使用匿名类型来投影我的查询,因为我认为它是linq to entities,但如果您正在处理像上面展示的列表,您可以在您的Client类上进行投影。


1
@Byyo,只是提醒一下,用这种方法,除非你遍历结果或调用ToList扩展方法,否则你的查询不会被实际执行,这是在你希望保持延迟执行的情况下。 - ocuenca

0

这个有效:

        var Grouped = (from Group in (from client in clients
                                      group client by client.Id into clientGroup
                                      select new { Id = clientGroup.Key, Sum = clientGroup.Sum(cc => cc.Amount) })
                       orderby Group.Sum descending
                       select Group).Take(3).ToList(); ;
        var Top3 = Grouped.Take(3).ToList();
        var Others = Grouped.Skip(3).ToList();

如果你想要将“others”作为一个列表。否则,将最后一行改为:

var Others = Grouped.Skip(3).Sum(g => g.Sum);

获取其他数的总和。


0

记住,GroupBy 返回的是一个分组而不是 Client 列表。你可以轻松地将分组投影回列表中,这种情况下使用匿名对象即可。

var clients = cList.GroupBy(x => x.ClientID)
                     .Select(x => new { ClientID = x.Key, AmountTotal = x.Sum(c => c.Amount) })
                     .OrderByDescending(x => x.AmountTotal);

var topThree = clients.Take(3);
var others = clients.Except(topThree);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接