Lo contrario de Intersect ()


276

Intersect se puede usar para encontrar coincidencias entre dos colecciones, así:

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

Sin embargo, lo que me gustaría lograr es lo contrario, me gustaría enumerar los elementos de una colección que faltan en la otra :

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

13
confirme si desea 4 como salida, o 1 y 4
Øyvind Bråthen

@ oyvind-knobloch-brathen Sí, solo me gustaría 4
Peter Bridger

23
Como nota al margen, este tipo de conjunto se denomina diferencia simétrica .
Mike T

19
Técnicamente hablando, una diferencia simétrica resultaría en [1, 4]. Dado que Peter solo quería los elementos en la matriz2 que no están en la matriz1 (es decir, 4), eso se llama un Complemento Relativo (también conocido como Diferencia teórica establecida)
rtorres

Respuestas:


377

Como se indicó, si desea obtener 4 como resultado, puede hacer lo siguiente:

var nonintersect = array2.Except(array1);

Si desea la no intersección real (también 1 y 4), entonces esto debería ser el truco:

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

Esta no será la solución más eficiente, pero para listas pequeñas debería funcionar bien.


2
¿Cuál sería una solución de mejor rendimiento? ¡Gracias!
shanabus

66
Probablemente pueda hacerlo más rápido utilizando dos bucles for anidados, pero el código será mucho más sucio que esto. Contando la legibilidad en esto también, claramente usaría esta variante ya que es muy fácil de leer.
Øyvind Bråthen

55
Solo un punto de margen para agregar, si tiene: int [] antes = {1, 2, 3}; int [] después = {2, 3, 3, 4}; e intenta usar Except para encontrar lo que se ha agregado a 'after' desde 'before': var diff = after.Except (before); 'diff' contiene 4, no 3,4. es decir, ten cuidado con los elementos duplicados que te dan resultados inesperados
Paul Ryland

¿Funcionaría mejor? array1.AddRange (array2.Except (array1));
LBW

86

Puedes usar

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

O puedes usar

var difference = new HashSet(a);
difference.SymmetricExceptWith(b);

2
Uso interesante de SymmetricExceptWith (), no habría pensado en ese enfoque
Peter Bridger

SymmetricExceptWithEs probablemente mi método favorito.
Ash Clarke

66
Comparé los dos en una aplicación real donde tenía un par de listas de aproximadamente 125 cadenas en cada uno de ellos. El uso del primer enfoque es en realidad más rápido para listas de ese tamaño, aunque en su mayoría es insignificante ya que ambos enfoques tienen menos de medio milisegundo.
Dan

1
Sería bueno si el BCL tuviera un método de extensión de Linq para esto. Parece una omisión.
Drew Noakes

Alguien comparó SymmetricExceptWith y lo encontró mucho más rápido: skylark-software.com/2011/07/linq-and-set-notation.html
Colin

11

Este código enumera cada secuencia solo una vez y se usa Select(x => x)para ocultar el resultado para obtener un método de extensión de estilo Linq limpio. Ya que usa HashSet<T>su tiempo de ejecución es O(n + m)si los hashes están bien distribuidos. Se omiten elementos duplicados en cualquiera de las listas.

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

6

Creo que podrías estar buscando Except:

El operador Excepto produce la diferencia establecida entre dos secuencias. Solo devolverá elementos en la primera secuencia que no aparecen en la segunda. Opcionalmente, puede proporcionar su propia función de comparación de igualdad.

Consulte este enlace , este enlace o Google, para obtener más información.


2

No estoy 100% seguro de lo que se supone que debe hacer su método NonIntersect (con respecto a la teoría de conjuntos): ¿es
B \ A (todo lo de B que no ocurre en A)?
En caso afirmativo, debería poder utilizar la operación Excepto (B.Excepto (A)).


Intersección de conjuntos == A∪B \ A∩B
amuliar el

2
/// <summary>
/// Given two list, compare and extract differences
/// http://stackoverflow.com/questions/5620266/the-opposite-of-intersect
/// </summary>
public class CompareList
{
    /// <summary>
    /// Returns list of items that are in initial but not in final list.
    /// </summary>
    /// <param name="listA"></param>
    /// <param name="listB"></param>
    /// <returns></returns>
    public static IEnumerable<string> NonIntersect(
        List<string> initial, List<string> final)
    {
        //subtracts the content of initial from final
        //assumes that final.length < initial.length
        return initial.Except(final);
    }

    /// <summary>
    /// Returns the symmetric difference between the two list.
    /// http://en.wikipedia.org/wiki/Symmetric_difference
    /// </summary>
    /// <param name="initial"></param>
    /// <param name="final"></param>
    /// <returns></returns>
    public static IEnumerable<string> SymmetricDifference(
        List<string> initial, List<string> final)
    {
        IEnumerable<string> setA = NonIntersect(final, initial);
        IEnumerable<string> setB = NonIntersect(initial, final);
        // sum and return the two set.
        return setA.Concat(setB);
    }
}

2

array1.NonIntersect (array2);

No intersector dicho operador no está presente en Linq que debe hacer

excepto -> unión -> excepto

a.except(b).union(b.Except(a));

-1
string left = "411329_SOFT_MAC_GREEN";
string right= "SOFT_MAC_GREEN";

string[] l = left.Split('_');
string[] r = right.Split('_');

string[] distinctLeft = l.Distinct().ToArray();
string[] distinctRight = r.Distinct().ToArray();

var commonWord = l.Except(r, StringComparer.OrdinalIgnoreCase)
string result = String.Join("_",commonWord);
result = "411329"
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.