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
}

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.


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

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

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.


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)).


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

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

-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"
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.