Linq - 分组并统计多个字段(单个总输出)

时间:2017-10-15 13:52:24

标签: c# linq razor

我有一个带有查询答案的应用程序(50个字段,名称如upa1,upa2,upd1,upd6等,可能的值" y"," n"和& #34; NA&#34)

我可以用这个来计算和计算一个字段:

foreach(var y in items.GroupBy(g => g.upa1)
                      .Select(group => new {upa1name = group.Key, upa1count = group.Count()})) {
    <div>These are the totals for upa1:</div>
    <div>@y.upa1name : @y.upa1count</div>
}

它将输出:

These are the totals for upa1:
y : 30
n : 11
na : 18

我可以手动重复此问题,但我需要计算&#34; y&#34;,&#34; n&#34;和&#34; na&#34;对于形成这一单一输出的所有问题:

These are the totals for all questions:
y : 1342
n : 879
na : 445

我知道已经有数百个关于这些问题的主题,但是信息太过紧张,并且在这个问题上有太多变化(不同的表,联接等)。关于多个字段的总和计数&#34;。

感谢。

另外,在旁注中,每行只在答案至少存在一次时出现,但我需要它才能显示即使它是&#34; y:0&#34;。这可能吗?

2 个答案:

答案 0 :(得分:1)

只有三个可能的答案,您可以在三个单独的查询中执行此操作:

foreach (var ans in new[] {"y", "n", "na"}) {
    var count = items.Sum(item =>
        (item.upa1==ans?1:0) + (item.upa2==ans?1:0) + (item.upd1==ans?1:0) + ...
    );
    <div>These are the totals for @ans:</div>
    <div>@ans : @count</div>
}

这应该运行得相当快。

答案 1 :(得分:1)

假设你有一个这样的课程:

public class Inquiry
{
    public string UpaName { get; set; }
    public string UpaValue { get; set; }
}

现在让我们用一些测试数据填充该列表:

var list = new List<Inquiry>()
{
    new Inquiry() { UpaName = "upa1", UpaValue = "y" },
    new Inquiry() { UpaName = "upa1", UpaValue = "y" },
    new Inquiry() { UpaName = "upa1", UpaValue = "n" },
    new Inquiry() { UpaName = "upa1", UpaValue = "na" },
    new Inquiry() { UpaName = "upa2", UpaValue = "y" },
    new Inquiry() { UpaName = "upa2", UpaValue = "n" },
    new Inquiry() { UpaName = "upa2", UpaValue = "na" },
    new Inquiry() { UpaName = "upa2", UpaValue = "na" },
    new Inquiry() { UpaName = "upa1", UpaValue = "y" },
    new Inquiry() { UpaName = "upa1", UpaValue = "y" },
    new Inquiry() { UpaName = "upa2", UpaValue = "n" },
    new Inquiry() { UpaName = "upa1", UpaValue = "y" },
    new Inquiry() { UpaName = "upa1", UpaValue = "y" },
};

我们可以创建另一个类来保存我们的键以及sumarized值。像这样:

[DebuggerDisplay("{UpaName,nq} y:{y,nq} n:{n,nq} na:{na,nq}")]//include Sysytem.Diagnostics
public class InquirySummary
{
    public string UpaName { get; set; }
    public int y { get; set; }
    public int n { get; set; }
    public int na { get; set; }
}

我们可以实例化一个键值字典,其中key是你的查询答案,值将是我们的InquirySummary类的一个实例。

var summary = new Dictionary<string, InquirySummary>();

我们要定义一个采用INquiry对象和InquirySummary对象的动作,并总结这些值。

Action<Inquiry, InquirySummary> sumarize = new Action<Inquiry, InquirySummary>((i, sum) =>
{
    if (i.UpaValue == "y")
        sum.y += 1;
    else if (i.UpaValue == "n")
        sum.n += 1;
    else
        sum.na += 1;
});

最后,您将拥有所有必要的东西来调用只能在列表中运行一次的聚合。

list.Aggregate(summary, (b, c) => 
{
    if (summary.ContainsKey(c.UpaName)) {
        var sum = summary[c.UpaName];
        sumarize(c, sum);
    }
    else
    {
        var sum = new InquirySummary();
        summary.Add(c.UpaName, sum);
        sumarize(c, sum);
    }
    return summary;
});

这基本上会将我们的字典作为种子,而不是我们开始循环遍历列表。首先 if 条件会检查密钥是否已存在于dicitonary中,而不是简单地调用该值上的sumarize操作。否则我们会创建一个新的InquirySummary对象,并且会对他产生影响。每次我们返回种子字典中的种子。