Противоположность Intersect ()

Пересечение можно использовать для поиска совпадений между двумя коллекциями, например:

// Assign two arrays.
int[] array1 = { 1, 2, 3 };
int[] array2 = { 2, 3, 4 };
// Call Intersect extension method.
var intersect = array1.Intersect(array2);
// Write intersection to screen.
foreach (int value in intersect)
{
    Console.WriteLine(value); // Output: 2, 3
}

Однако я хотел бы добиться противоположного: я хотел бы перечислить элементы из одной коллекции, которые отсутствуют в другой:

// Assign two arrays.
int[] array1 = { 1, 2, 3 };
int[] array2 = { 2, 3, 4 };
// Call "NonIntersect" extension method.
var intersect = array1.NonIntersect(array2); // I've made up the NonIntersect method
// Write intersection to screen.
foreach (int value in intersect)
{
    Console.WriteLine(value); // Output: 4
}

person Peter Bridger    schedule 11.04.2011    source источник
comment
пожалуйста, подтвердите, хотите ли вы 4 в качестве вывода или 1 и 4   -  person Øyvind Bråthen    schedule 11.04.2011
comment
@ oyvind-knobloch-brathen Да, мне бы хотелось только 4   -  person Peter Bridger    schedule 11.04.2011
comment
Кстати, этот тип набора называется симметричной разницей.   -  person Mike T    schedule 15.08.2012
comment
Технически говоря, симметричная разность приведет к [1, 4]. Поскольку Питеру нужны были только элементы в array2, которых нет в array1 (т.е. 4), это называется Относительное дополнение (также известное как теоретико-множественное различие)   -  person rtorres    schedule 17.07.2014


Ответы (6)


Как уже говорилось, если вы хотите получить в результате 4, вы можете сделать так:

var nonintersect = array2.Except(array1);

Если вам нужно настоящее непересечение (также как 1, так и 4), то это должно помочь:

var nonintersect = array1.Except(array2).Union( array2.Except(array1));

Это не будет самым эффективным решением, но для небольших списков оно должно работать нормально.

person Øyvind Bråthen    schedule 11.04.2011
comment
какое решение будет лучше? Спасибо! - person shanabus; 04.01.2012
comment
Вероятно, вы можете сделать это быстрее, используя два вложенных цикла for, но код будет намного грязнее, чем этот. Принимая во внимание удобочитаемость, я бы явно использовал этот вариант, так как он очень легко читается. - person Øyvind Bråthen; 04.01.2012
comment
Просто добавление боковой линии, если у вас есть: int [] before = {1, 2, 3}; int [] после = {2, 3, 3, 4}; и вы пытаетесь использовать Except, чтобы найти, что было добавлено в «после» с «до»: var diff = after.Except (before); 'diff' содержит 4, а не 3,4. то есть следите за повторяющимися элементами, дающими неожиданные результаты - person Paul Ryland; 09.08.2013
comment
Будет ли это работать лучше? array1.AddRange (array2.Except (array1)); - person LBW; 15.06.2018

Ты можешь использовать

a.Except(b).Union(b.Except(a));

Или вы можете использовать

var difference = new HashSet(a);
difference.SymmetricExceptWith(b);
person sehe    schedule 11.04.2011
comment
Интересное использование SymmetricExceptWith (), я бы не подумал об этом подходе - person Peter Bridger; 11.04.2011
comment
SymmetricExceptWith, наверное, мой любимый метод. - person Ash Clarke; 22.04.2013
comment
Я сравнил их в реальном приложении, где у меня было несколько списков примерно по 125 строк в каждом из них. Использование первого подхода на самом деле быстрее для списков такого размера, хотя в основном это несущественно, поскольку оба подхода составляют менее половины миллисекунды. - person Dan; 31.05.2013
comment
Было бы неплохо, если бы в BCL был для этого метод расширения Linq. Вроде упущение. - person Drew Noakes; 30.06.2015
comment
Кто-то протестировал SymmetricExceptWith и обнаружил, что это намного быстрее: skylark-software .com / 2011/07 / linq-and-set-notation.html. - person Colin; 18.07.2017

Этот код перечисляет каждую последовательность только один раз и использует Select(x => x), чтобы скрыть результат, чтобы получить чистый метод расширения в стиле Linq. Поскольку он использует HashSet<T>, его время выполнения равно O(n + m), если хэши хорошо распределены. Повторяющиеся элементы в любом списке опускаются.

public static IEnumerable<T> SymmetricExcept<T>(this IEnumerable<T> seq1,
    IEnumerable<T> seq2)
{
    HashSet<T> hashSet = new HashSet<T>(seq1);
    hashSet.SymmetricExceptWith(seq2);
    return hashSet.Select(x => x);
}
person CodesInChaos    schedule 11.04.2011

Думаю, вы ищете Except:

Оператор Except производит установленную разницу между двумя последовательностями. Он вернет только элементы из первой последовательности, которых нет во второй. При желании вы можете предоставить свою собственную функцию сравнения на равенство.

Просмотрите эту ссылку, this link или Google, чтобы получить дополнительную информацию.

person Grant Thomas    schedule 11.04.2011

Я не уверен на 100%, что должен делать ваш метод NonIntersect (относительно теории множеств) - это
B \ A (все из B, чего нет в A)?
Если да, то вам следует уметь использовать операцию Except (B.Except (A)).

person Frank Schmitt    schedule 11.04.2011
comment
Пересечение множеств == A∪B \ A∩B - person amuliar; 04.01.2019

array1.NonIntersect (array2);

Nonintersect такого оператора нет в Linq, вы должны сделать

кроме -> объединение -> кроме

a.except(b).union(b.Except(a));
person safder    schedule 15.11.2014