Kebalikan dari Intersect ()

276

Intersect dapat digunakan untuk menemukan kecocokan antara dua koleksi, seperti:

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

Namun yang ingin saya capai adalah kebalikannya, saya ingin mendaftar item dari satu koleksi yang hilang dari yang lain :

// 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
sumber
13
harap konfirmasikan jika Anda ingin 4 sebagai output, atau 1 dan 4
Øyvind Bråthen
@ oyvind-knobloch-brathen Ya, saya hanya ingin 4
Peter Bridger
23
Sebagai catatan, jenis perangkat ini disebut Perbedaan Simetris .
Mike T
19
Secara teknis, Perbedaan Simetris akan menghasilkan [1, 4]. Karena Peter hanya menginginkan elemen-elemen di array2 yang tidak ada di array1 (yaitu, 4), itu disebut Relative Complement (alias Set-Theoretic Difference)
rtorres

Jawaban:

377

Seperti yang dinyatakan, jika Anda ingin mendapatkan 4 sebagai hasilnya, Anda dapat melakukan seperti ini:

var nonintersect = array2.Except(array1);

Jika Anda ingin non-persimpangan nyata (juga keduanya 1 dan 4), maka ini yang harus dilakukan:

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

Ini tidak akan menjadi solusi yang paling berhasil, tetapi untuk daftar kecil itu akan berfungsi dengan baik.

Øyvind Bråthen
sumber
2
apa yang akan menjadi solusi dengan kinerja yang lebih baik? Terima kasih!
shanabus
6
Anda mungkin dapat melakukannya lebih cepat dengan menggunakan dua bersarang untuk loop, tetapi kodenya akan lebih kotor dari ini. Menghitung keterbacaan ke dalam ini juga, saya jelas akan menggunakan varian ini karena sangat mudah dibaca.
Øyvind Bråthen
5
Hanya satu poin tambahan untuk ditambahkan, Jika Anda memiliki: int [] before = {1, 2, 3}; int [] after = {2, 3, 3, 4}; dan Anda mencoba menggunakan Kecuali untuk menemukan apa yang telah ditambahkan ke 'setelah' sejak 'sebelum': var diff = after.Except (before); 'diff' mengandung 4, bukan 3,4. yaitu hati-hati terhadap elemen duplikat yang memberi Anda hasil yang tidak terduga
Paul Ryland
Apakah ini berkinerja lebih baik? array1.AddRange (array2.Except (array1));
BBLR
86

Kamu bisa memakai

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

Atau bisa Anda gunakan

var difference = new HashSet(a);
difference.SymmetricExceptWith(b);
lihat
sumber
2
Penggunaan yang menarik dari SymmetricExceptWith (), saya tidak akan memikirkan pendekatan itu
Peter Bridger
SymmetricExceptWithmungkin metode favorit saya.
Ash Clarke
6
Saya membandingkan keduanya dalam aplikasi nyata di mana saya memiliki beberapa daftar sekitar 125 string di masing-masing. Menggunakan pendekatan pertama sebenarnya lebih cepat untuk daftar ukuran itu, meskipun sebagian besar tidak signifikan karena keduanya mendekati di bawah setengah milidetik.
Dan
1
Akan lebih baik jika BCL memiliki metode ekstensi Linq untuk ini. Sepertinya kelalaian.
Drew Noakes
Seseorang membuat benchmark SymmetricExceptWith dan menemukannya jauh lebih cepat: skylark-software.com/2011/07/linq-and-set-notation.html
Colin
11

Kode ini menghitung setiap urutan hanya sekali dan menggunakan Select(x => x)untuk menyembunyikan hasilnya untuk mendapatkan metode ekstensi gaya Linq bersih. Karena menggunakan HashSet<T>runtime-nya adalah O(n + m)jika hash didistribusikan dengan baik. Elemen duplikat di kedua daftar dihilangkan.

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
sumber
6

Saya pikir Anda mungkin mencari Except:

Operator Kecuali menghasilkan perbedaan set antara dua urutan. Itu hanya akan mengembalikan elemen dalam urutan pertama yang tidak muncul di urutan kedua. Anda secara opsional dapat menyediakan fungsi perbandingan kesetaraan Anda sendiri.

Lihat tautan ini , tautan ini , atau Google, untuk informasi lebih lanjut.

Grant Thomas
sumber
2

Saya tidak 100% yakin apa yang seharusnya dilakukan oleh metode NonIntersect Anda (mengenai teori himpunan) - apakah
B \ A (semuanya dari B yang tidak terjadi di A)?
Jika ya, maka Anda harus dapat menggunakan operasi Kecuali (B.Kecuali (A)).

Frank Schmitt
sumber
Persimpangan set == A∪B \ A∩B
amuliar
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
sumber
2

array1.NonIntersect (array2);

Nonintersect operator tersebut tidak ada di Linq yang harus Anda lakukan

kecuali -> gabungan -> kecuali

a.except(b).union(b.Except(a));
lebih aman
sumber
-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
sumber