C# 根据条件将行从一个IEnumerable添加到另一个IEnumerable
我有两个数组C# 根据条件将行从一个IEnumerable添加到另一个IEnumerable,c#,linq,c#-4.0,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 = "
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 }
};
我想做的是检查data2
中的每个不同的产品
和年份
,如果data1
中的产品
和年份
的任何组合存在任何行,但不在data2
中,则将该行添加到data2
例如。。
在data2
中,不同的产品是Product1
和Product2
,不同的年份是Year1
,Year2
,Year3
和Year4
在数据1中存在一行{Product=“Product 2”,Year=2009,Sales=522}
,该行在data2
中不存在,因此我希望将其添加到data2
我能做的是在两个变量中得到不同的产品和年份
然后对这两个循环中的每个循环执行一次检查,检查组合是否存在于data1中,但不存在于data2中,如果存在,则将其添加到data2中
我希望得到的是一个LINQ查询,它可以为我完成这项工作,而不是分别执行两个不同的查询,然后为每个循环执行两个查询
谢谢您可以在一个查询中实现这一点。然而,它将是次优的,因为对于
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();
var uniqueProd=newhashset(data2.Select(d=>d.Product));
var uniqueYear=newhashset(data2.Select(d=>d.Year));
var knownPairs=新哈希集(
data2.Select(d=>Tuple.Create(d.Product,d.Year))
);
var newData2=data2.Concat(
数据1.其中(d=>
uniqueProd.Contains(d.Product)//产品在那里
&&uniqueYear.Contains(d.Year)//年份在那里
&&!knownPairs.Contains(Tuple.Create(d.Product,d.Year))//组合不存在
)
).ToArray();
这个解决方案在时间上是O(m+n),在空间上也是O(n)。我不会对效率提出任何要求,但它可以在单个查询中实现 如果您满足于让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);
或者,您可以排除预先存在的数据2匹配,并使用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
);
奥托,我忍不住要计时。如果我们将使用Union作为1调用,使用Concat的时间占73%,创建哈希集的时间占827%,提取唯一的对集的时间占54%,跳过.Distinct()的时间占27%,尽管数据集的速度太慢,无法分辨其中的一些差异
拔出配对并卸下:
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
);
您的意思是直接将其添加到另一个数组中,还是只需要一个包含
data2
中的项和data1
中的某些项的新集合?后者更容易,因为数组的大小是固定的。我同意后者,事实上后者更好。而且{Product=“Product 1”,Year=2009,Sales=1212}
存在于两个数组中,所以我不明白为什么你说它需要添加到Data2
对不起,我的意思是{Product=“Product 2”,Year=2009,Sales=522},同时编辑问题您应该将Union
与自定义相等比较器一起使用,但由于您使用的是匿名类型,相等比较器有点不同。因此,我认为最好是搜索实现匿名类型的IEqualityComparer
。+1用于使用HashSet。我正在努力理解HashSet。你能评论一下你方和我方的不同之处吗?谢谢@赢取您的解决方案将包括来自data1
的年份/产品组合,即使是data2
中不存在的配对。具体来说,我认为OP不希望最后一行出现Product3
,因为Product3
不在data2
的产品中。在此之前,我从未见过Hashset的使用。它比列表快吗。如果您能看看我的一个老问题()并告诉我Hashset的用法是否对第二次和第三次查询特别有用,我将不胜感激。您能告诉我您是如何获得计时信息的吗。。我希望在我的数据集上使用相同的方法。我使用LinqPad和内置的Util.ElapsedTime来计算不同查询的计时。通常,您可以使用StopWatch类为部分代码计时,或者使用VisualStudio评测。