我有两个包含对象元素的列表,一个大列表称为List1,另一个小列表称为List2。我需要根据在对象中返回基于布尔值的函数中定义的条件,使用List2中的值更新List1中的值。我想出了以下实现,对于较大的列表,这确实需要很多时间。
检查项目是否将被更新的功能
private static bool CheckMatch(Item item1, Item item2) {
//do some stuff here and return a boolean
}
我正在用来更新商品的查询
在下面的代码段中,我需要使用List2(小列表)中的一些值更新List1(大列表)
foreach(var item1 in List1)
{
var matchingItems = List2.Where(item2 => CheckMatch(item1, item2));
if (matchingItems.Any())
{
item1.IsExclude = matchingItems.First().IsExcluded;
item1.IsInclude = matchingItems.First().IsIncluded;
item1.Category = matchingItems.First().Category;
}
}
我希望我能得到一个比这更好的解决方案。我还需要保持List1
中元素的位置这里是我在做什么的示例Here is sample of what I'm doing
正如LP13的答案所指出的那样,您通过重新执行查询而不是一次执行并缓存结果来进行大量重新计算。
但是这里更大的问题是,如果您在n
中有List1
个项目,并且在m
中有List2
个潜在匹配项,并且您正在寻找any匹配项,那么最坏的情况肯定是n * m
匹配。如果n
和m
大,则它们的乘积会更大。而且由于我们正在寻找any匹配项,因此最坏的情况是没有匹配项;您肯定会尝试所有m
可能性。
这是可以避免的费用吗?也许,但是只有当我们知道一些要利用的trick并且您已经使问题变得如此抽象时-我们有两个列表和一个关系,而没有关于列表或关系的信息-没有可以利用的结构。
就是说:如果您碰巧知道List2
中有一个元素可能与List1
中的many个项目匹配,请将该元素放在first处。 Any
或FirstOrDefault
在获得第一个匹配项后将停止执行Where
查询,因此您可以将O(n * m)
问题变成O(n)
问题。
在不了解什么是关系的情况下,很难说如何提高性能。
更新:评论者指出,如果我们知道该关系是等价关系,我们可以做得更好。是等价关系吗?也就是说,假设我们有您的方法可以检查两个项目。我们可以保证以下条件吗?
CheckMatch(a, a)
始终为真。CheckMatch(a, b)
始终与CheckMatch(b, a)
相同CheckMatch(a, b)
为真并且CheckMatch(b, c)
为真,那么CheckMatch(a, c)
始终为真如果我们具有这三个条件,那么您可以做得更好。这样的关系将元素划分为equivalence classes。您要做的是将List1
和List2
中的每个项目与规范值关联。对于等价类的每个成员,该规范值都是相同的。然后,您可以从该词典中进行快速查找并快速解决问题。
但是,如果您的关系不是等价关系,则此方法无效。
您可以尝试这个吗?当仅执行.Where
时,它会产生IEnumerable
,然后在IEnumerable上执行First()
和Any()
foreach(var item1 in List1)
{
var matchingItem = List2.Where(item2 => CheckMatch(item1, item2)).FirstOrDefault();
if (matchingItem != null)
{
item1.IsExclude = matchingItem.IsExcluded;
item1.IsInclude = matchingItem.IsIncluded;
item1.Category = matchingItem.Category;
}
}