Ответ 1
Вторая имеет лучшую производительность в больших списках, чем первая. Intersect
помещает элементы одного списка в хеш-таблицу перед проверкой других элементов списка для членства.
Я хочу знать, можно ли найти хотя бы один элемент в первом списке во втором списке.
Я вижу два способа сделать это. Скажем, наши списки:
List<string> list1 = new[] { "A", "C", "F", "H", "I" };
List<string> list2 = new[] { "B", "D", "F", "G", "I" };
Первый подход использует цикл:
bool isFound = false;
foreach (item1 in list1)
{
if (list2.Contains(item1))
{
isFound = true;
break;
}
}
Второй использует Linq напрямую:
bool isFound = list1.Intersect(list2).Any();
Первый из них длинный, чтобы писать, а не очень просто/легко читаться. Второй - короткий и понятный, но производительность будет низкой, особенно в больших списках.
Что может быть изящным способом сделать это?
Вторая имеет лучшую производительность в больших списках, чем первая. Intersect
помещает элементы одного списка в хеш-таблицу перед проверкой других элементов списка для членства.
Кажется странным критиковать производительность LINQ, когда оригинал явно (худший случай) O (n * m); подходом LINQ я ожидал бы использовать HashSet<T>
в списке, а затем использовать блок потокового итератора, поэтому производительность должна быть 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;
}
}
Вы также можете оптимизировать этот код, сделав меньший список в хэш-набор, а не всегда используя list2.
Принятый ответ велик, однако он не работает с Linq-to-sql, так как нет отображения для Intersect
.
В этом случае вы должны использовать:
bool isFound = table.Any(row => list2.Contains(row.FieldWithValue));
Это скомпилируется в WHERE EXSITS
Это еще один способ узнать, существует ли элемент одного списка в другом списке.
bool present = List1.Any(t => List2.Any(y => y == t));