linq-组成并计数多个字段(单个总数输出)[英] Linq - Group by and count over multiple fields (output on single total)

本文是小编为大家收集整理的关于linq-组成并计数多个字段(单个总数输出)的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

我有一个带有询问答案的应用程序(50个字段,具有upa1,upa2,upd1,upd6等的名称,具有可能的值" y"," n"和" na").

我可以得到并计数一个字段:

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

我可以手动重复所有问题,但是我需要计算所有问题的" y"," n"和" na"的数量,以形成这个单个输出:

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

我知道这些问题已经有数百个主题,但是信息太伸展了,并且在此问题上的变化太多(不同的表,连接等).在"多个字段"的"总和"上.

谢谢.

另外,在旁注上,只有在答案至少存在一次时才出现,但是即使它是" y:0",我也需要显示它.这可能吗?

推荐答案

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

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>
}

这应该快速运行.

其他推荐答案

假设您有这样的课程:

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" },
};

我们可以创建另一个可以保存我们的密钥和总价值的类.这样的东西:

[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; }
}

我们可以比实例化关键值的字典,其中关键将是您的查询答案,而值将是我们的询问类的一个实例.

var summary = new Dictionary<string, 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;
});

这基本上将使我们的字典作为种子,而不是我们开始循环浏览列表.第一个如果条件会检查键是否已经存在于dicitonary中,并且与小调用该值的sumarize诉讼相比.否则,我们将创建一个新的询问对象,并将其交给他.每次我们返回案例字典中的种子.

本文地址:https://www.itbaoku.cn/post/1557208.html

问题描述

I have an app with an inquiry answers (50 fields, with names like upa1, upa2, upd1, upd6, etc, with possible values "y", "n" and "na").

I can get and count one single field with this:

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>
}

And it will output this:

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

I can repeat this for all questions manually, but I need to count the number of "y", "n" and "na" for all questions to form this single output:

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

I know there are already hundreds of topics about these issues, but the information is far too stretched and over way too many variations on this matter (different tables, joins, etc). Nothin on the "sum count over multiple fields".

Thanks.

Also, on a side note, each line only appears if the answer exists at least once, but I need it to show even if it is a "y : 0". Is this possible?

推荐答案

With only three possible answers you can do this in three separate queries:

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>
}

This should run reasonably fast.

其他推荐答案

Lets say you have a class like this:

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

Now lets populate that list with some test data:

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" },
};

We can create another class that would hold our key along with sumarized values. Something like this:

[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; }
}

We could than instantiate a dictionary of key values where key would be your inquiry answer and the value would be an instance of our InquirySummary class.

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

We would than define an action that would take INquiry object and InquirySummary object and would summarize the values.

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;
});

Finally you would have all the neccessary things to call an aggregate that would run only once through your list.

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;
});

This would basically give our dictionary as seed and than we would start looping through the list. First if condition would check if the key already exists in the dicitonary and than would simpy call the sumarize action on that value. Otherwise we would create a new InquirySummary object and would sumarize into him. Each time we are returning the seed which is in our case dictionary.