Sự đối lập của Intersect ()


275

Intersect có thể được sử dụng để tìm kết quả khớp giữa hai bộ sưu tập, như vậy:

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

Tuy nhiên, điều tôi muốn đạt được thì ngược lại, tôi muốn liệt kê các mục từ một bộ sưu tập còn thiếu từ bộ sưu tập khác :

// 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
vui lòng xác nhận nếu bạn muốn 4 làm đầu ra, hoặc 1 và 4
yvind Bråthen

@ oyvind-Knobloch-brathen Vâng, tôi chỉ muốn 4
Peter Bridger

23
Là một lưu ý phụ, loại tập hợp này được gọi là Sự khác biệt đối xứng .
Mike T

19
Về mặt kỹ thuật, sự khác biệt đối xứng sẽ dẫn đến [1, 4]. Vì Peter chỉ muốn các phần tử trong mảng2 không nằm trong mảng1 (tức là 4), nên đó được gọi là Bổ sung tương đối (hay còn gọi là Sự khác biệt về lý thuyết)
rtorres 17/07/14

Câu trả lời:


376

Như đã nêu, nếu bạn muốn có được 4 kết quả, bạn có thể làm như thế này:

var nonintersect = array2.Except(array1);

Nếu bạn muốn giao điểm không thực (cả cả 1 và 4), thì điều này nên thực hiện thủ thuật:

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

Đây sẽ không phải là giải pháp hiệu quả nhất, nhưng đối với các danh sách nhỏ, nó sẽ hoạt động tốt.


2
Điều gì sẽ là một giải pháp hiệu quả tốt hơn? Cảm ơn!
shanabus

6
Bạn có thể có thể làm điều đó nhanh hơn bằng cách sử dụng hai vòng lặp lồng nhau, nhưng mã sẽ bẩn hơn thế này. Tính khả năng đọc cũng vậy, tôi rõ ràng sẽ sử dụng biến thể này vì nó rất dễ đọc.
Øyvind Bråthen

5
Chỉ cần một điểm bên lề để thêm, Nếu bạn có: int [] before = {1, 2, 3}; int [] after = {2, 3, 3, 4}; và bạn cố gắng sử dụng Ngoại trừ để tìm những gì đã được thêm vào 'sau' kể từ 'trước': var diff = after.Except (trước); 'diff' chứa 4, không phải 3,4. tức là coi chừng các yếu tố trùng lặp mang lại cho bạn kết quả bất ngờ
Paul Ryland

Điều này sẽ thực hiện tốt hơn? mảng1.AddRange (mảng2.Except (mảng1));
LBW

86

Bạn có thể dùng

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

Hoặc bạn có thể sử dụng

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

2
Việc sử dụng SymmetricExceptWith () thú vị, tôi sẽ không nghĩ đến cách tiếp cận đó
Peter Bridger

SymmetricExceptWithcó lẽ là phương pháp yêu thích của tôi
Ash Clarke

6
Tôi đã so sánh hai trong một ứng dụng thực tế nơi tôi có một vài danh sách gồm khoảng 125 chuỗi trong mỗi ứng dụng. Sử dụng cách tiếp cận đầu tiên thực sự nhanh hơn đối với các danh sách có kích thước đó, mặc dù nó hầu như không đáng kể vì cả hai cách tiếp cận trong đó dưới nửa mili giây.
Dan

1
Sẽ rất tuyệt nếu BCL có phương pháp mở rộng Linq cho việc này. Có vẻ như là một thiếu sót.
Drew Noakes

Có người làm chuẩn SymmetricExceptWith và thấy nó nhanh hơn nhiều: skylark-software.com/2011/07/linq-and-set-notation.html
Colin

11

Mã này liệt kê mỗi chuỗi chỉ một lần và sử dụng Select(x => x)để ẩn kết quả để có được phương thức mở rộng kiểu Linq sạch. Vì nó sử dụng HashSet<T>thời gian chạy của nó là O(n + m)nếu các giá trị băm được phân phối tốt. Các yếu tố trùng lặp trong một trong hai danh sách được bỏ qua.

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

Tôi nghĩ rằng bạn có thể đang tìm kiếm Except:

Toán tử Ngoại trừ tạo ra sự khác biệt thiết lập giữa hai chuỗi. Nó sẽ chỉ trả về các phần tử trong chuỗi đầu tiên không xuất hiện trong phần thứ hai. Bạn có thể tùy chọn cung cấp chức năng so sánh bình đẳng của riêng bạn.

Kiểm tra liên kết này , liên kết này hoặc Google, để biết thêm thông tin.


2

Tôi không chắc chắn 100% phương pháp NonIntersect của bạn phải làm gì (liên quan đến lý thuyết tập hợp) - đó có phải là
B \ A (mọi thứ từ B không xảy ra trong A) không?
Nếu có, thì bạn sẽ có thể sử dụng thao tác Ngoại trừ (B.Except (A)).


Giao điểm của các bộ == A∪B \ A∩B
đặc biệt

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

mảng1.NonIntersect (mảng2);

Nonintersect toán tử như vậy không có trong Linq bạn nên làm

ngoại trừ -> liên minh -> ngoại trừ

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"
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.