根据条件将行从一个IEnumerable添加到另一个IEnumerable

时间:2016-10-21 16:25:53

标签: c# linq c#-4.0

我有两个阵列..

var data1 = new[] { 
        new { Product = "Product 1", Year = 2009, Sales = 1212 },
        new { Product = "Product 2", Year = 2009, Sales = 522 },
        new { Product = "Product 1", Year = 2010, Sales = 1337 },
        new { Product = "Product 2", Year = 2011, Sales = 711 },
        new { Product = "Product 2", Year = 2012, Sales = 2245 },
        new { Product = "Product 3", Year = 2012, Sales = 1000 }
    };

var data2 = new[] { 
        new { Product = "Product 1", Year = 2009, Sales = 1212 },
        new { Product = "Product 1", Year = 2010, Sales = 1337 },
        new { Product = "Product 2", Year = 2011, Sales = 711 },
        new { Product = "Product 2", Year = 2012, Sales = 2245 }
    };

我想要做的是检查Product中的每个不同Yeardata2,以及Product和{{1}的任何组合是否存在任何行在Year但不在data1中,然后将该行添加到data2

实施例.. 在data2中,不同的产品是data2Product1,不同的年份是Product2Year1Year2Year3。< / p>

在data1中存在行Year4{ Product = "Product 2", Year = 2009, Sales = 522 }中不存在,因此我希望将其添加到data2

我能做的是获得两个变量的不同产品和年份。

然后为两个循环执行a并检查data1中是否存在组合,但是不存在于data2中,如果存在,则将其添加到data2。

我想得到的是单个LINQ查询,它可以为我完成这项工作,而不是分别做两个不同的事情,然后为每个循环做几个。

由于

2 个答案:

答案 0 :(得分:2)

您可以在单个查询中使用此功能。然而,它将是次优的,因为对于data1中的每个项目,您需要检查三个条件,这可能需要遍历整个data2以获得O(m * n)时间复杂度(空间复杂性仍然是O(1))。

你可以避免使用相同的循环:

var uniqueProd = new HashSet<string>(data2.Select(d=>d.Product));
var uniqueYear = new HashSet<int>(data2.Select(d=>d.Year));
var knownPairs = new HashSet<Tuple<string,int>>(
    data2.Select(d=>Tuple.Create(d.Product, d.Year))
);
var newData2 = data2.Concat(
    data1.Where(d =>
        uniqueProd.Contains(d.Product)                       // The product is there
    &&  uniqueYear.Contains(d.Year)                          // The year is there
    && !knownPairs.Contains(Tuple.Create(d.Product, d.Year)) // Combination is not there
    )
).ToArray();

该解决方案的时间为O(m + n),空间也为O(n)。

答案 1 :(得分:1)

我不会对效率提出任何要求,但可以在一次查询中提出。

如果您满意让Union处理删除重复项,您可以这样做:

var newd2 = data2.Union(
    from d1 in data1
    where
        (from d2p in data2 from d2y in data2 
         select new { d2p.Product, d2y.Year })
        .Distinct().Any(mp => mp.Product == d1.Product && mp.Year == d1.Year)
    select d1);

或者,您可以排除预先存在的data2匹配并使用Concat

var newd2 = data2.Concat(
    from d1 in data1
    where
        (from d2p in data2 from d2y in data2 select new { d2p.Product, d2y.Year })
        .Distinct().Any(mp => mp.Product == d1.Product && mp.Year == d1.Year) &&
        !data2.Any(mp => mp.Product == d1.Product && mp.Year == d1.Year)
    select d1
    );
OTOH,我无法抗拒某些时间。如果我们使用Union作为1调用,使用Concat的时间从73%开始不同,创建HashSets使用827%的时间并且拉出唯一对的设置需要54%,跳过.Distinct()需要27%,尽管数据集太慢,无法区分其中的一些。

拉出对并倾倒Distinct:

var newdd = (from d2p in data2 from d2y in data2 select new { d2p.Product, d2y.Year });
var newd2 = data2.Concat(
    from d1 in data1
    where
        newdd.Any(mp => mp.Product == d1.Product && mp.Year == d1.Year) &&
        !data2.Any(mp => mp.Product == d1.Product && mp.Year == d1.Year)
    select d1
    );