左外连接和分组依据

时间:2011-04-18 14:31:10

标签: c# .net linq .net-4.0

我有以下类定义:

public class MyData  
{  
    public DateTime Expiration { get; private set; }  
    public string Name { get; private set; }  
    public double Price { get; private set; }  
    public double Quantity { get; private set; }  
}

我需要加上一份年份清单:

IEnumerable<int> years= Enumerable.Range(1, 20);

结果将最终显示在网格中,y轴代表Name字段,x轴代表年份。每个单元格将是Quantity和年份的汇总Price * Name

我目前正在努力学习语法。我开始时将MyData的实例加入到这些年份并按如下方式分组:

var myData = GetData();
var query = from data in myData
            join year in years on (data.Expiration.Year - DateTime.Now.Year) + 1 equals year
            group data by new { Year = (data.Expiration.Year - DateTime.Now.Year) + 1
                              , Name = data.Name } into grouped
            select new {Name = grouped.Key.Name
                      , Year = grouped.Key.Year
                      , Value = grouped.Sum(d => d.Quanity * d.Price) };

这为我提供了根据需要汇总的数据,但显然排除了MyData的所有实例都不包含匹配Expiration的任何年份。

我似乎无法弄清楚如何修改我的查询以获取我需要的数据。一旦我得到了包含的年份,我的聚合就会崩溃,而且我有效地在所有年份中得到Price的所有Quantity的{​​{1}}的总和,而不是Name在逐年的基础上。

3 个答案:

答案 0 :(得分:7)

有一种方法可以在LINQ中保持连接,但这是真的 - 语法不是很清楚。您的查询将如下所示:

var query = from year in years
            join data in myData
                on year equals (data.Expiration.Year - DateTime.Now.Year) + 1
                into year_data
            from y_d in year_data.DefaultIfEmpty()
            group y_d by new
            {
                Year = year,
                Name = y_d == null ? "" : y_d.Name
            }
            into grouped
            select new
            {
                Name = grouped.Key.Name,
                Year = grouped.Key.Year,
                Value = grouped.Sum(d => d == null ? 0 : d.Quantity * d.Price)
            };

答案 1 :(得分:1)

您还可以采用不同的方法 - 而不是加入,首先选择所有年份并过滤掉您的数据,同时计算每个数据对象/年的聚合。像这样:

from year in years select new 
{ 
    Year = year, 
    Items = myData
        .GroupBy(i => i.Name)
        .Select(grouped => new 
        { 
            Name = grouped.Key, 
            Aggregate = grouped
                .Where(d => (d.Expiration.Year - DateTime.Now.Year) + 1 == year)
                .Sum(d => d.Price * d.Quantity)
        })
};

答案 2 :(得分:0)

如果你无法解决问题......替换它......

为每个名称和年份构建MyData的虚拟条目,其中quantity = 0且price = 0

将它们放入列表并替换此行:

var query = from data in myData

这一行:

var query = from data in myData.Concat(dummyList)