У меня есть 2 Объекта списка:
List<int> lst1 = new List<int>();
List<int> lst2 = new List<int>();
Скажем, у них есть значения:
lst1.Add(1);
lst1.Add(2);
lst1.Add(3);
lst1.Add(4);
lst2.Add(1);
lst2.Add(4);
Я должен получить объект, содержащий "отличный" список обоих из них; таким образом, в этом случае возврат был бы Списком {2, 3}.
Существует ли простой способ сделать это? Или я должен выполнить итерации через каждое значение списков и выдержать сравнение?
Я открыт для использования ObjectQuery, LINQ, и т.д. когда эти списки прибывают из базы данных и могли потенциально быть несколькими сотнями к нескольким тысячам записей долго.
Спасибо!
Ахмад почти прав с Except
, я полагаю - но это не даст вам элементов, которые есть в lst2
, но нет в lst1
. Поэтому в приведенном вами примере, если вы добавите 5 к lst2
, я представляю, что вы хотите получить результат {2, 3, 5}. В этом случае вы хотите получить симметричную разность. Я не думаю, что в LINQ to Objects есть способ сделать это непосредственно за один вызов, но вы все же можете этого добиться. Вот простой, но неэффективный способ сделать это:
lst1.Union(lst2).Except(lst1.Intersect(lst2)).ToList();
(Очевидно, что ToList()
нужен только в том случае, если вам действительно нужен List
, а не IEnumerable
.)
Прочитать это можно так: "Мне нужны элементы, которые есть в любом списке, но не в обоих. "
Возможно, что эффективнее было бы использовать Concat
- который все равно будет работать, поскольку Except
- это оператор, основанный на множестве, который возвращает только отдельные результаты:
lst1.Concat(lst2).Except(lst1.Intersect(lst2)).ToList();
EDIT: благодаря комментариям, чтобы получить симметричную разность, нужно проделать дополнительную работу, кроме использования Except
. Если добавить дополнительное значение во 2-й список, то исключение само по себе будет неверным. Чтобы получить правильный результат, попробуйте сделать следующее:
var list1 = new List<int>(Enumerable.Range(1,4));
var list2 = new List<int> { 1, 4, 6 };
var result = list1.Except(list2).Union(list2.Except(list1));
Вышеприведенный результат возвращает {2, 3, 6}.
Обратите внимание, что вам нужно добавить ToList()
, если вам действительно нужен List
, иначе приведенная выше операция вернет IEnumerable
.
Используйте метод Enumerable.Except, который выдает заданную разность двух последовательностей:
var result = lst1.Except(lst2);
Если результаты поступают из базы данных, лучше обработать их там. Это будет намного быстрее по сравнению с работой с памятью, особенно если будет много результатов.
Если вам нужно обработать их в своем коде, вы можете использовать i4o - Indexed LINQ , чтобы ускорить процесс.
В Linq:
var distinct = lst2.Contact(lst1).Distinct().ToList();
(Из вашего объяснения следует, что вам нужны уникальные элементы в обоих списках. Но из вашего примера следует, что вам нужно объединение
обоих списков).
LINQ был бы простым способом, сгруппировав каждый элемент на основе его значения, а затем выбрав только те, которые имеют один элемент:
from i in lst1.Concat(lst2)
group i by i into g
where !g.Skip(1).Any()
select g.Key;
Использование Skip здесь позволит вам убедиться, что существует не более одного элемента; если в последовательности 1 или меньше элементов, возвращается пустая последовательность, для которой Any вернет false.