Das Gegenteil von Intersect ()

275

Intersect kann verwendet werden, um Übereinstimmungen zwischen zwei Sammlungen zu finden, z. B.:

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

Was ich jedoch erreichen möchte, ist das Gegenteil. Ich möchte Elemente aus einer Sammlung auflisten, die in der anderen fehlen :

// 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
}
Peter Bridger
quelle
13
Bitte bestätigen Sie, ob Sie 4 als Ausgabe oder 1 und 4
Øyvind Bråthen
@ oyvind-knobloch-brathen Ja, ich möchte nur 4
Peter Bridger
23
Als Randnotiz wird diese Art von Menge als symmetrische Differenz bezeichnet .
Mike T
19
Technisch gesehen würde ein symmetrischer Unterschied zu [1, 4] führen. Da Peter nur die Elemente in Array2 haben wollte, die nicht in Array1 (dh 4) enthalten sind, wird dies als relatives Komplement (auch bekannt als Set-Theoretic Difference) bezeichnet
rtorres

Antworten:

376

Wie bereits erwähnt, können Sie Folgendes tun, wenn Sie als Ergebnis 4 erhalten möchten:

var nonintersect = array2.Except(array1);

Wenn Sie die reale Nicht-Schnittmenge (auch 1 und 4) möchten, sollte dies den Trick tun:

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

Dies ist nicht die leistungsstärkste Lösung, aber für kleine Listen sollte sie einwandfrei funktionieren.

Øyvind Bråthen
quelle
2
Was wäre eine leistungsstärkere Lösung? Vielen Dank!
Shanabus
6
Sie können es wahrscheinlich schneller machen, indem Sie zwei verschachtelte for-Schleifen verwenden, aber der Code wird viel schmutziger sein. Wenn ich auch die Lesbarkeit mit einbeziehe, würde ich diese Variante eindeutig verwenden, da sie sehr einfach zu lesen ist.
Øyvind Bråthen
5
Nur ein Nebenpunkt zum Hinzufügen, wenn Sie haben: int [] before = {1, 2, 3}; int [] after = {2, 3, 3, 4}; und Sie versuchen, Except zu verwenden, um herauszufinden, was zu 'after' seit 'before' hinzugefügt wurde: var diff = after.Except (before); 'diff' enthält 4, nicht 3,4.
Paul Ryland
Würde dies besser funktionieren? array1.AddRange (array2.Except (array1));
LBW
86

Sie können verwenden

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

Oder Sie können verwenden

var difference = new HashSet(a);
difference.SymmetricExceptWith(b);
sehe sehen
quelle
2
Interessante Verwendung von SymmetricExceptWith (), ich hätte nicht an diesen Ansatz gedacht
Peter Bridger
SymmetricExceptWithist wahrscheinlich meine Lieblingsmethode.
Ash Clarke
6
Ich habe die beiden in einer realen Anwendung verglichen, in der ich ein paar Listen mit jeweils etwa 125 Zeichenfolgen hatte. Die Verwendung des ersten Ansatzes ist für Listen dieser Größe tatsächlich schneller, obwohl er größtenteils unbedeutend ist, da beide Ansätze weniger als eine halbe Millisekunde betragen.
Dan
1
Wäre schön, wenn die BCL dafür eine Linq-Erweiterungsmethode hätte. Es scheint eine Auslassung zu sein.
Drew Noakes
Jemand hat SymmetricExceptWith verglichen
Colin
11

Dieser Code listet jede Sequenz nur einmal auf und Select(x => x)versteckt das Ergebnis, um eine saubere Erweiterungsmethode im Linq-Stil zu erhalten. Da es HashSet<T>seine Laufzeit verwendet, ist, O(n + m)wenn die Hashes gut verteilt sind. Doppelte Elemente in beiden Listen werden weggelassen.

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);
}
CodesInChaos
quelle
6

Ich denke, Sie suchen vielleicht Except:

Der Operator Except erzeugt die eingestellte Differenz zwischen zwei Sequenzen. Es werden nur Elemente in der ersten Sequenz zurückgegeben, die in der zweiten nicht erscheinen. Optional können Sie Ihre eigene Gleichstellungsvergleichsfunktion bereitstellen.

Weitere Informationen finden Sie unter diesem Link , diesem Link oder Google.

Grant Thomas
quelle
2

Ich bin nicht 100% sicher, was Ihre NonIntersect-Methode tun soll (in Bezug auf die Mengenlehre) - ist es
B \ A (alles von B, was in A nicht vorkommt)?
Wenn ja, sollten Sie in der Lage sein, die Operation Except (B.Except (A)) zu verwenden.

Frank Schmitt
quelle
Schnittmenge von Mengen == A∪B \ A∩B
eigenartig
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);
    }
}
Alcedo
quelle
2

array1.NonIntersect (array2);

Ein solcher Operator, der keinen Schnittpunkt aufweist, ist in Linq nicht vorhanden

außer -> Vereinigung -> außer

a.except(b).union(b.Except(a));
sicherer
quelle
-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"
Kiflay
quelle