ตรงข้ามของ Intersect ()


276

สามารถใช้ Intersect เพื่อค้นหารายการที่ตรงกันระหว่างสองคอลเล็กชันดังนี้:

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

อย่างไรก็ตามสิ่งที่ฉันต้องการบรรลุคือสิ่งที่ตรงกันข้ามฉันต้องการแสดงรายการจากคอลเล็กชันหนึ่งที่หายไปจากรายการอื่น :

// 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
โปรดยืนยันว่าคุณต้องการ 4 เป็นผลลัพธ์หรือ 1 และ 4
ØyvindBråthen

@ oyvind-knobloch-brathen ใช่ฉันต้องการ 4 เท่านั้น
Peter Bridger

23
ขณะที่ทราบด้านประเภทของชุดนี้จะเรียกว่าเป็นความแตกต่างสมมาตร
Mike T

19
เทคนิคการพูดความแตกต่างแบบสมมาตรจะส่งผลให้ [1, 4] ตั้งแต่ปีเตอร์ต้องการเพียงองค์ประกอบใน array2 ที่ไม่ได้อยู่ใน array1 (เช่น 4) จึงเรียกว่าRelative Complement (aka Set-Theoretic Difference)
rtorres

คำตอบ:


377

ตามที่ระบุไว้หากคุณต้องการได้รับ 4 เป็นผลคุณสามารถทำสิ่งนี้:

var nonintersect = array2.Except(array1);

หากคุณต้องการจุดตัดที่ไม่ใช่ของจริง (เช่นทั้ง 1 และ 4) คุณควรทำดังนี้

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

นี่ไม่ใช่วิธีแก้ปัญหาที่มีประสิทธิภาพมากที่สุด แต่สำหรับรายการขนาดเล็กควรใช้งานได้ดี


2
สิ่งที่จะเป็นทางออกที่ดีกว่า? ขอบคุณ!
shanabus

6
คุณสามารถทำได้เร็วขึ้นโดยใช้ซ้อนกันสองลูปสำหรับลูป แต่รหัสจะสกปรกกว่านี้ การนับการอ่านในเรื่องนี้ฉันจะใช้ตัวแปรนี้อย่างชัดเจนเพราะอ่านง่ายมาก
ØyvindBråthen

5
เพียงแค่ปลีกย่อยที่จะเพิ่มถ้าคุณมี: int [] before = {1, 2, 3}; int [] after = {2, 3, 3, 4}; และคุณพยายามใช้ยกเว้นเพื่อค้นหาสิ่งที่ถูกเพิ่มใน 'after' ตั้งแต่ 'before': var diff = after.Except (before); 'diff' มี 4 ไม่ใช่ 3,4 เช่นระวังองค์ประกอบที่ซ้ำกันให้ผลลัพธ์ที่คุณคาดไม่ถึง
Paul Ryland

สิ่งนี้จะทำงานได้ดีขึ้นหรือไม่ array1.AddRange (array2.Except (array1));
LBW

86

คุณสามารถใช้ได้

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

หรือคุณสามารถใช้

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

2
การใช้ SymmetricExceptWith () ที่น่าสนใจฉันจะไม่นึกถึงวิธีการนั้น
Peter Bridger

SymmetricExceptWithอาจเป็นวิธีที่ฉันชอบ
Ash Clarke

6
ฉันเปรียบเทียบทั้งสองในแอปพลิเคชันจริงที่ฉันมีรายการสองสามรายการเกี่ยวกับ 125 สตริงในแต่ละรายการ การใช้วิธีแรกนั้นเร็วกว่าสำหรับรายการที่มีขนาดนั้นถึงแม้ว่าวิธีการทั้งสองจะไม่มีนัยสำคัญส่วนใหญ่ซึ่งน้อยกว่าครึ่งมิลลิวินาที
ด่าน

1
คงจะดีถ้า BCL มีวิธีการขยาย Linq สำหรับเรื่องนี้ ดูเหมือนว่าจะละเว้น
Drew Noakes

มีคนเปรียบเทียบ SymmetricExceptWith แล้วและพบว่ามันเร็วขึ้นมาก: skylark-software.com/2011/07/linq-and-set-notation.html
Colin

11

รหัสนี้แจกแจงแต่ละลำดับเพียงครั้งเดียวและใช้Select(x => x)เพื่อซ่อนผลลัพธ์เพื่อรับเมธอดส่วนขยายแบบ Linq แบบใหม่ทั้งหมด เนื่องจากมันใช้HashSet<T>รันไทม์ของมันคือO(n + m)ถ้า hash ถูกกระจายอย่างดี องค์ประกอบที่ซ้ำกันในรายการใดรายการหนึ่งจะถูกละเว้น

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

ฉันคิดว่าคุณอาจกำลังมองหาExcept:

ตัวดำเนินการยกเว้นสร้างความแตกต่างที่กำหนดไว้ระหว่างสองซีเควนซ์ มันจะคืนองค์ประกอบในลำดับแรกที่ไม่ปรากฏในลำดับที่สองเท่านั้น คุณสามารถเลือกที่จะให้ฟังก์ชั่นการเปรียบเทียบความเท่าเทียมกันของคุณเอง

ตรวจสอบการเชื่อมโยงนี้ , การเชื่อมโยงนี้หรือ Google สำหรับข้อมูลเพิ่มเติม


2

ฉันไม่แน่ใจ 100% ว่าวิธีการตัดต่อที่ไม่ควรทำของคุณ (เกี่ยวกับทฤษฎีเซต) - มันเป็น
B \ A (ทุกอย่างจาก B ที่ไม่ได้เกิดขึ้นใน A) หรือไม่
ถ้าใช่คุณควรใช้การดำเนินการยกเว้น (B.Except (A))


ทางแยกของเซต == 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 ผู้ประกอบการดังกล่าวไม่ได้อยู่ใน Linq ที่คุณควรทำ

ยกเว้น -> union -> ยกเว้น

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"
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.