Intersect () öğesinin tersi


276

Kesişim, iki koleksiyon arasındaki eşleşmeleri bulmak için kullanılabilir, örneğin:

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

Ancak elde etmek istediğim tersi, bir koleksiyondan diğerinden eksik olan öğeleri listelemek istiyorum :

// 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
çıktı olarak 4 veya 1 ve 4
Øyvind Bråthen

@ oyvind-knobloch-brathen Evet, sadece 4 istiyorum
Peter Bridger

23
Yan not olarak, bu tür kümelere Simetrik Fark denir .
Mike T

19
Teknik olarak, simetrik bir fark ortaya çıkacaktır [1, 4]. Peter sadece
dizi2'deki dizi1'deki

Yanıtlar:


377

Belirtildiği gibi, sonuç olarak 4 almak istiyorsanız, bunu yapabilirsiniz:

var nonintersect = array2.Except(array1);

Gerçek kavşak olmayan (hem 1 hem de 4) istiyorsanız, bu hile yapmalıdır:

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

Bu en performanslı çözüm olmayacaktır, ancak küçük listeler için iyi çalışmalıdır.


2
daha iyi performans gösteren bir çözüm ne olurdu? Teşekkürler!
shanabus

6
Büyük olasılıkla döngüler için iç içe iki kullanarak daha hızlı yapabilirsiniz, ancak kod bundan daha kirli olacaktır. Okunabilirliği de buna dahil ederek, okuması çok kolay olduğu için bu varyantı açıkça kullanacağım.
Øyvind Bråthen

5
Eklemek için yalnızca bir kenar çizgisi noktası, Varsa: int [] önce = {1, 2, 3}; int [] sonra = {2, 3, 3, 4}; ve önce 'beri' beri 'sonraya' eklenenleri bulmak için Hariç tutmaya çalışın: var diff = after.Except (önce); 'diff' 3,4 değil 4 içerir. yani size beklenmedik sonuçlar veren yinelenen elemanlar için dikkat
Paul Ryland

Bu daha iyi performans gösterir mi? array1.AddRange (array2.Except (array1));
LBW

86

Kullanabilirsiniz

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

Veya kullanabilirsiniz

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

2
SymmetricExceptWith () 'in ilginç kullanımı, bu yaklaşımı düşünmezdim
Peter Bridger

SymmetricExceptWithmuhtemelen en sevdiğim yöntem.
Ash Clarke

6
Ben her birinde yaklaşık 125 dizeleri bir çift listeleri vardı gerçek bir uygulamada iki karşılaştırdı. İlk yaklaşımı kullanmak, bu boyuttaki listeler için aslında daha hızlıdır, ancak yarım milisaniyenin altındaki her iki yaklaşımda da çoğunlukla önemsizdir.
Dan

1
BCL bunun için bir Linq uzatma yöntemi olsaydı iyi olurdu. Bir ihmal gibi görünüyor.
Drew Noakes

Birisi SymmetricExceptWith'i karşılaştırdı ve çok daha hızlı buldu: skylark-software.com/2011/07/linq-and-set-notation.html
Colin

11

Bu kod, her diziyi yalnızca bir kez numaralandırır ve Select(x => x)temiz bir Linq tarzı uzantı yöntemi elde etmek için sonucu gizlemek için kullanır . Çalışma HashSet<T>zamanını kullandığı O(n + m)için karma iyi dağıtılmışsa. Her iki listedeki yinelenen öğeler atlanır.

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

Sanırım arıyor olabilirsiniz Except:

Except operatörü, iki dizi arasında ayarlanan farkı üretir. Yalnızca ilk sırada yer alan öğeleri ikinci sırada görünmeyecektir. İsteğe bağlı olarak kendi eşitlik karşılaştırma işlevinizi sağlayabilirsiniz.

Daha fazla bilgi için bu bağlantıya , bu bağlantıya veya Google'a göz atın .


2

NonIntersect yönteminizin (set teorisi ile ilgili) ne yapması gerektiğinden% 100 emin değilim -
B \ A (A'dan gerçekleşmeyen B'den gelen her şey)?
Evet ise, Hariç tutma işlemini (B. Hariç (A)) kullanabilmeniz gerekir.


Kümelerin kesişimi == 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);

Bu tür bir operatörün Linq'de bulunmaması gerekir.

hariç -> sendika -> hariç

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"
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.