Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/340.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/0/performance/5.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#_Performance_Linq - Fatal编程技术网

C# 如何确定列表中的一个元素是否在另一个列表中?

C# 如何确定列表中的一个元素是否在另一个列表中?,c#,performance,linq,C#,Performance,Linq,我想知道第一个列表中是否至少有一个元素可以在第二个列表中找到 我可以看到两种方法。假设我们的列表是: List<string> list1 = new[] { "A", "C", "F", "H", "I" }; List<string> list2 = new[] { "B", "D", "F", "G", "I" }; 第二个直接使用Linq: bool isFound = list1.Intersect(list2).Any(); 第一个很长,写起来不太直接/容

我想知道第一个列表中是否至少有一个元素可以在第二个列表中找到

我可以看到两种方法。假设我们的列表是:

List<string> list1 = new[] { "A", "C", "F", "H", "I" };
List<string> list2 = new[] { "B", "D", "F", "G", "I" };
第二个直接使用Linq:

bool isFound = list1.Intersect(list2).Any();
第一个很长,写起来不太直接/容易阅读。第二个是简短而清晰的,但表现将很低,特别是在大名单上


什么可能是一种优雅的方法呢?

第二种方法在大型列表上的性能比第一种方法更好
Intersect
在检查另一个列表的元素的成员资格之前,将一个列表的元素放入哈希表。

当原始列表明显(最坏情况)为O(n*m)时,批评LINQ的性能似乎有些奇怪;我希望LINQ方法在列表上使用
HashSet
,然后使用流迭代器块-因此性能应该是O(n+m)-即更好。

我认为第二种方法对于大型列表会更快。因为第一个是O(list1.Count*list2.Count),而第二个是O(list1.Count+list2.Count)。第二个需要更多的内存

linq的开销通常是手工编写的代码的一个常数乘法因子。我猜第二个代码比命令式代码慢最多两倍,甚至可能不是这样。它使用
O(list1.Count+list2.Count)
内存,如果您仔细编写代码以降低内存使用率,同时保持线性性能,则可以将内存缩减为
O(Min(list1,list2))

在大型列表上,此代码应该相对较快:

bool isFound = false;
HashSet<string> set2=new HashSet<string>(list2);
foreach (item1 in list1)
{
    if (set2.Contains(item1))
    {
        isFound = true;
        break;
    }
}
bool isFound=false;
HashSet set2=新的HashSet(列表2);
foreach(列表1中的项目1)
{
if(集合2.包含(项目1))
{
isFound=true;
打破
}
}

您可以通过将较小的列表设置为哈希集而不是始终使用list2来进一步优化此代码。

接受的答案非常好,但是它不适用于Linq到sql,因为没有
Intersect
的映射。 在这种情况下,您应该使用:

bool isFound = table.Any(row => list2.Contains(row.FieldWithValue));

这将被编译为
中存在的

这是另一种了解一个列表的元素是否存在于另一个列表中的方法

bool present = List1.Any(t => List2.Any(y => y == t));

我认为第二种方法对于大型列表会更快。因为第一个是
O(list1.Count*list2.Count)
,而第二个是
O(list1.Count+list2.Count)
。第二个需要更多的内存。如果您真的想使用LINQ像第一个示例一样进行搜索,请使用
bool isfind=list1.Any(list2.Contains)但当然,这个变量,就像原始代码一样,具有二次性能。我认为在第二种情况下,将计算两个列表的交集,然后才执行
Any
。我错了吗?交叉口的计算很慢。我认为它首先从列表2中创建一个哈希集,然后在列表1中返回并添加到哈希集。@MainMa-是的,你错了。它将散列第一个集合,然后使用迭代器块在第二个集合上进行假脱机。在每一点上,您只返回一个匹配项。迭代器块在返回内容之前不会运行到完成。不需要计算集合中的完整匹配集。
Any()
运行到完成的唯一时间是它返回
false
——否则它将在第一次匹配时短路序列。是的,您错了。您可以想象它的工作方式与
break
在循环中的工作方式相同。交叉点是惰性计算的,一旦发现第一个元素存在于其中,
Any()
返回,不再检查。
bool present = List1.Any(t => List2.Any(y => y == t));