如何用另一个列表高效地更新列表C#
我有两个包含对象元素的列表,一个是大列表,我们称之为List1,另一个是小列表List2。 我需要根据函数中定义的条件,使用List2中的值更新List1中的值,该函数基于对象中的值返回布尔值。 我已经提出了下面的实现,对于更大的列表来说,这确实花费了很多时间 检查项目是否会更新的功能如何用另一个列表高效地更新列表C#,c#,list,linq,big-o,C#,List,Linq,Big O,我有两个包含对象元素的列表,一个是大列表,我们称之为List1,另一个是小列表List2。 我需要根据函数中定义的条件,使用List2中的值更新List1中的值,该函数基于对象中的值返回布尔值。 我已经提出了下面的实现,对于更大的列表来说,这确实花费了很多时间 检查项目是否会更新的功能 private static bool CheckMatch(Item item1, Item item2) { //do some stuff here and return a boolean } 我用来
private static bool CheckMatch(Item item1, Item item2) {
//do some stuff here and return a boolean
}
我用来更新项目的查询
在下面的代码段中,我需要使用List2(小列表)中的一些值更新List1(大列表)
我希望我能找到一个比这更好的解决方案。我还需要维护列表1中元素的位置
这是我正在做的示例
你能试试这个吗?当您只执行
。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;
}
}
正如LP13的回答所指出的,通过重新执行查询而不是执行一次并缓存结果,您正在进行大量的重新计算 但这里更大的问题是,如果您在
List1
中有n
项,在List2
中有m
潜在匹配项,并且您正在寻找任何匹配项,那么在最坏的情况下,您肯定会进行n*m
匹配。如果n
和m
较大,则其乘积较大。既然我们在寻找任何一场比赛,最糟糕的情况就是没有比赛;您一定会尝试所有的m
可能性
这成本可以避免吗?也许吧,但前提是我们知道一些可以利用的技巧,而且你已经把问题抽象化了——我们有两个列表和一个关系,没有关于列表或关系的信息——我们没有可以利用的结构
这就是说:如果您碰巧知道List2
中有一个元素可能与List1
中的许多项目相匹配,那么请将该元素放在第一位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)
List1
和List2
中的每个项目与规范值相关联。该规范值对于等价类的每个成员都是相同的。从那本字典你可以快速查找并快速解决你的问题
但是,如果你的关系不是等价关系,这就不起作用。从技术上讲,你可以用
FirstOrDefault
matchingItem替换其中的,matchingItem是一个相同对象的列表,这就是为什么我要用第一个来澄清这个(好的)答案:查询不是答案,它是一个问题。每次你在matchingItems
上说First
或Any
,查询都会重新开始,因为LINQ认为这次的答案可能不同。这个解决方案缓存答案,因此只运行一次查询。很多问题归结为匹配的事实。假设您在List1
中有一百万项,在List2
中有一千项。List1
中平均有多少元素得到匹配?在所有这些匹配中,有多少是与List2
中的同一对象的匹配?也就是说,List1
中匹配的每个项目在List2
中是否都有一个基本上唯一的匹配项,或者在List2
中是否有一个元素几乎匹配所有内容,或者什么?如果你能给我们看一下CheckMatch
的实际代码,这就为我们提供了其他情况下无法获得的优化机会。在一般情况下,要使它比O(len(List1)*len(List2))更好,真的没有什么办法了。。。如果您能找到某种方法让条目正确地实现IEqualityComparer
(使用正确的GetHashCode
,这样就可以使用字典),那么您可能应该提到,正确的IEqualityComparer
将提供O(n+m)解决方案,而不是O(n)在最好的情况下,最好的比赛向前推进。@AlexeiLevenkov:对,这就是我想说的,我们需要更多地了解这种关系。这可能不是一个等价关系!但是你说得对,应该更明确地调用它。@EricLippert我的数据没有等价关系,请检查更新的问题以获得示例代码的链接。
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;
}
}