Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/260.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何用另一个列表高效地更新列表C#_C#_List_Linq_Big O - Fatal编程技术网

如何用另一个列表高效地更新列表C#

如何用另一个列表高效地更新列表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 } 我用来

我有两个包含对象元素的列表,一个是大列表,我们称之为List1,另一个是小列表List2。 我需要根据函数中定义的条件,使用List2中的值更新List1中的值,该函数基于对象中的值返回布尔值。 我已经提出了下面的实现,对于更大的列表来说,这确实花费了很多时间

检查项目是否会更新的功能

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;
    }
}