LINQ将两个数据集中的使用数据合并为一个

时间:2016-09-21 13:14:08

标签: c# linq

我拥有的:

以下型号的两个列表:

int    SubscriptionId
int    ItemId
double Usage
double EffectiveRate
string ResourceName
string UnitOfMeasure

第一个包含上个月的使用数据,如下所示:

SubscriptionId  ItemId  Usage  EffectiveRate  ResourceName  UnitOfMesaure
_________________________________________________________________________
1               1       2      2,75           R1            U1
1               2       3      1,50           R2            U2

秒包含当月的使用数据,如下所示:

SubscriptionId  ItemId  Usage  EffectiveRate  ResourceName  UnitOfMesaure
_________________________________________________________________________
1               1       5      2,75           R1            U1
1               3       2      1,50           R3            U3

我想要的是什么:

这应该合并在这样的列表中:

SubscriptionId  ItemId  UsageThis  UsageLast  EffRate  ResName  UOM
_________________________________________________________________________
1               1       5          2          2,75     R1       U1
1               2       0          3          1,50     R2       U2
1               3       2          0          1,50     R3       U3

我拥有的:

//data for both months available
if (resourcesThisMonth.Any() && resourcesLastMonth.Any())
{
    //join both months
    resources = from resourceLastMonth in resourcesLastMonth
                join resourceThisMonth in resourcesThisMonth
                on new { resourceLastMonth.SubscriptionId, resourceLastMonth.ItemId } equals new { resourceThisMonth.SubscriptionId, resourceThisMonth.ItemId }
                select new Resource
                {
                    SubscriptionId = resourceThisMonth.SubscriptionId,
                    ItemId = resourceThisMonth.ItemId,
                    UsageThisMonth = resourceThisMonth.Usage,
                    UsageLastMonth = resourceLastMonth.Usage,
                    EffectiveRate = resourceThisMonth.EffectiveRate,
                    ResourceName = resourceThisMonth.ResourceName,
                    UnitOfMeasure = resourceThisMonth.UnitOfMeasure
                };

    //resources only last month available
    var resourcesOnlyLastMonth = resourcesLastMonth.Where(r => !resourcesThisMonth.Where(s => s.ItemId == r.ItemId && s.SubscriptionId == r.SubscriptionId).Any())
                                 .Select(r => new Resource
                                 {
                                     SubscriptionId = r.SubscriptionId,
                                     ItemId = r.ItemId,
                                     UsageThisMonth = 0.0,
                                     UsageLastMonth = r.Units,
                                     EffectiveRate = r.EffectiveRate,
                                     ResourceName = r.ResourceName,
                                     UnitOfMeasure = r.UnitOfMeasure
                                 });

    //resources only this month available
    var resourcesOnlyThisMonth = resourcesThisMonth.Where(r => !resourcesLastMonth.Where(s => s.ItemId == r.ItemId && s.SubscriptionId == r.SubscriptionId).Any())
                                 .Select(r => new Resource
                                 {
                                     SubscriptionId = r.SubscriptionId,
                                     ItemId = r.ItemId,
                                     UsageThisMonth = r.Usage,
                                     UsageLastMonth = 0.0,
                                     EffectiveRate = r.EffectiveRate,
                                     ResourceName = r.ResourceName,
                                     UnitOfMeasure = r.UnitOfMeasure
                                 });

    //union data
    resources = resources.Union(resourcesOnlyLastMonth);
    resources = resources.Union(resourcesOnlyThisMonth);
}
//data for last month available
else if (resourcesLastMonth.Any())
{
    resources = from resource in resourcesLastMonth
                select new Resource
                {
                    SubscriptionId = resource.SubscriptionId,
                    ItemId = resource.ItemId,
                    UsageThisMonth = 0.0,
                    UsageLastMonth = resource.Usage,
                    EffectiveRate = resource.EffectiveRate,
                    ResourceName = resource.ResourceName,
                    UnitOfMeasure = resource.UnitOfMeasure
                };
}
//data for this month available
else if (resourcesThisMonth.Any())
{
    resources = from resource in resourcesThisMonth
                select new Resource
                {
                    SubscriptionId = resource.SubscriptionId,
                    ItemId = resource.ItemId,
                    UsageThisMonth = resource.Usage,
                    UsageLastMonth = 0.0,
                    EffectiveRate = resource.EffectiveRate,
                    ResourceName = resource.ResourceName,
                    UnitOfMeasure = resource.UnitOfMeasure
                };
}
//no data available
else
{
    resources = new List<Resource>();
}

问题:

这是非常多的代码 - 应该更少,到目前为止任何可能的解决方案都失败了


感谢您的帮助!

2 个答案:

答案 0 :(得分:1)

public class ExampleClass
{
    public int Id1 { get; set; }
    public int Id2 { get; set; }
    public int Usage { get; set; }
    public int UsageThis { get; set; }
    public int UsageLast { get; set; }
}


        List<ExampleClass> listThisMonth = new List<ExampleClass>
        {
            new ExampleClass{Id1=1, Id2=1,Usage=7, UsageThis=1, UsageLast=0},
            new ExampleClass{Id1=2, Id2=2,Usage=4, UsageThis=2, UsageLast=0},
            new ExampleClass{Id1=3, Id2=3,Usage=1, UsageThis=3, UsageLast=0},
        };

        List<ExampleClass> listLastMonth = new List<ExampleClass>
        {
            new ExampleClass{Id1=1, Id2=1,Usage=3, UsageThis=1, UsageLast=1},
            new ExampleClass{Id1=4, Id2=4,Usage=3, UsageThis=4, UsageLast=3},
            new ExampleClass{Id1=2, Id2=2,Usage=1, UsageThis=8, UsageLast=6},
        };

        var result = listThisMonth.Select(a=>new {value=a, list=1})
            .Union(listLastMonth.Select(a => new { value = a, list = 2 }))
            .GroupBy(a => new { Id1 = a.value.Id1, Id2 = a.value.Id2 })
            .Select(x => new ExampleClass
            {
                Id1 = x.Key.Id1,
                Id2 = x.Key.Id2,
                UsageThis = x.Any(o => o.list == 1) ? x.First(o => o.list == 1).value.Usage : 0,
                UsageLast = x.Any(o => o.list == 2) ? x.First(o => o.list == 2).value.Usage : 0,
                Usage = x.Sum(o=>o.value.Usage)
            }).ToList();

        //id1   id2 current last    sum
        //1     1   7       3       10
        //2     2   4       1       5
        //3     3   1       0       1
        //4     4   0       3       3

答案 1 :(得分:0)

在我看来,你正在寻找的是一个完整的外部联接。不幸的是,看起来LINQ没有这方面的构造。因此,有几个选项:LINQ - Full Outer Join

对于您的方案,您看起来有一些冗余代码。您应该能够使用两个外部联接来执行联合以获取正确的结果集。例如:

// Left join the current month with the last month
var currentMonth = 
    from current in resourcesThisMonth
    join last in resourcesLastMonth on new { current.SubscriptionId, current.ItemId } equals new { last.SubscriptionId, last.ItemId } into outer
    from o in outer.DefaultIfEmpty()
    select new Resource
    {
        SubscriptionId = current.SubscriptionId,
        ItemId = current.ItemId,
        UnitsThisMonth = current.Units,
        UnitsLastMonth = o?.Units ?? 0, // Replace NULL with 0
        EffectiveRate = current.EffectiveRate,
        ResourceName = current.ResourceName,
        UnitOfMeasure = current.UnitOfMeasure
    };

// Reverse of the first join.  Last month LEFT JOIN Current month
var lastMonth = 
    from last in resourcesLastMonth
    join current in resourcesThisMonth on new { last.SubscriptionId, last.ItemId } equals new { current.SubscriptionId, current.ItemId } into outer
    from o in outer.DefaultIfEmpty()
    select new Resource
    {
        SubscriptionId = last.SubscriptionId,
        ItemId = last.ItemId,
        UnitsThisMonth = o?.Units ?? 0, // Replace NULL with 0
        UnitsLastMonth = last.Units,
        EffectiveRate = o?.EffectiveRate ?? last.EffectiveRate,
        ResourceName = o?.ResourceName ?? last.ResourceName,
        UnitOfMeasure = o?.UnitOfMeasure ?? last.UnitOfMeasure
    };

// Union them together to get a full join
var resources = currentMonth.Union(lastMonth);