2009-03-25 24 views
45

Hãy nói rằng tôi có hai mảng này:Lấy "diff" giữa hai mảng trong C#?

var array1 = new[] {"A", "B", "C"}; 
var array2 = new[] {"A", "C", "D"}; 

Tôi muốn để có được sự khác biệt giữa hai người. Tôi biết tôi có thể viết điều này chỉ trong một vài dòng mã, nhưng tôi muốn chắc chắn rằng tôi không thiếu một tính năng ngôn ngữ được xây dựng trong hoặc một phương pháp mở rộng LINQ.

Lý tưởng nhất, tôi sẽ kết thúc với ba kết quả như sau:

  • Items không array1, nhưng trong array2 ("D")
  • Items không array2, nhưng trong array1 (" B ")
  • Các mục nằm trong cả hai

Cảm ơn bạn trước!

Trả lời

86

Nếu bạn có LINQ sẵn có cho mình, bạn có thể sử dụng ExceptDistinct. Các bộ bạn yêu cầu trong câu hỏi lần lượt là:

- array2.Except(array1) 
- array1.Except(array2) 
- array1.Intersect(array2) 
+0

Bạn có biết loại bảo đảm hiệu suất là gì không?Có lẽ ngoại trừ sẽ phải thực hiện một bản sao được sắp xếp của mỗi mảng đầu tiên. Tôi không thể tìm thấy bất kỳ điều này trên MSDN. – Eclipse

+1

Không, nó không tạo bản sao được sắp xếp. Nó tạo ra một tập hợp từ chuỗi bị loại trừ, và sau đó lặp qua chuỗi nguồn, sinh ra bất kỳ phần tử nào không nằm trong chuỗi bị loại trừ. –

+3

(Khi tôi nói "set" nghĩa là "hash set".) –

10

từ MSDN 101 LINQ samples ....

public void Linq52() { 
    int[] numbersA = { 0, 2, 4, 5, 6, 8, 9 }; 
    int[] numbersB = { 1, 3, 5, 7, 8 }; 

    IEnumerable<int> aOnlyNumbers = numbersA.Except(numbersB); 

    Console.WriteLine("Numbers in first array but not second array:"); 
    foreach (var n in aOnlyNumbers) { 
     Console.WriteLine(n); 
    } 
} 
3

tôi đã làm những điều tương tự như sau với bộ rất lớn dữ liệu. Nếu bạn đang đối phó với một vài nghìn hoặc hơn, hãy sử dụng công cụ Linq vì nó rõ ràng hơn nhiều. Nhưng nếu bạn biết rằng mảng của bạn được sắp xếp trước, việc chạy một kết hợp như thế này có thể làm nhanh hơn đáng kể, vì nó chỉ làm cho một đi qua dữ liệu và không cần phân bổ bộ nhớ nhiều như phiên bản LINQ.

int iA = 0; 
int iB = 0; 
List<int> inA = new List<int>(); 
List<int> inB = new List<int>(); 
List<int> inBoth = new List<int>(); 
while (iA < numbersA.Length && iB < numbersB.Length) 
{ 
    if (numbersA[iA] < numbersB[iB]) 
    { 
     inA.Add(numbersA[iA++]); 
    } 
    else if (numbersA[iA] == numbersB[iB]) 
    { 
     inBoth.Add(numbersA[iA++]); 
     ++iB; 
    } 
    else 
    { 
     inB.Add(numbersB[iB++]); 
    } 
} 
while (iA < numbersA.Length) 
{ 
    inA.Add(numbersA[iA++]); 
} 
while (iB < numbersB.Length) 
{ 
    inB.Add(numbersB[iB++]); 
} 

Một lần nữa, điều này thực sự chỉ cần nếu bạn đang xử lý hàng trăm nghìn giá trị.

3

Dưới đây là các tiêu chuẩn của phương pháp mở rộng LINQ. Các kết quả thu được trong quá trình phát triển một chương trình thực sự.

Các thử nghiệm: 2 danh sách (lst1 và lst2) mỗi khoảng 2.50000 đối tượng. Mỗi đối tượng (class Key) chứa một chuỗi và một số nguyên. Danh sách thứ hai chủ yếu chứa các mục tương tự như mục đầu tiên, nhưng một số mục nhập mới được thêm vào và một số mục được xóa.

Tôi đã thử nghiệm phương pháp Mở rộng ngoại lệ.

var ngoại trừ = lst2.Except (lst1);

Danh sách lst = except.ToList();

Hai dòng này tạo ra 600 danh sách các mục “bổ sung mới”. Tôi đã hẹn giờ nó bằng cách sử dụng đối tượng StopWatch. Tốc độ đáng kinh ngạc: 220 ms. Máy tính tôi sử dụng không phải là "Gonzales nhanh". Core 2 Duo T7700 - 2,4 GHz.

Lưu ý:

Đây là khóa lớp, triển khai IEquatable i-face.

public class Key : IEquatable<Key> 
{ 
    public int Index { get; private set; } 
    public string Name { get; private set; } 

    public Key(string keyName, int sdIndex) 
    { 
     this.Name = keyName; 
     this.Index = sdIndex; 
    } 

// IEquatable implementation 
    public bool Equals(Key other) 
    { 
     //Check whether the compared object is null. 
     if (Object.ReferenceEquals(other, null)) return false; 
     //Check whether the compared object references the same data. 
     if (Object.ReferenceEquals(this, other)) return true; 
     //Check whether the products' properties are equal. 
     return Index.Equals(other.Index) && Name.Equals(other.Name); 
    } 

    // If Equals() returns true for a pair of objects 
    // then GetHashCode() must return the same value for these objects. 
    public override int GetHashCode() 
    { 
     //Get hash code for the name field if it is not null. 
     int hashKeyName = Name == null ? 0 : Name.GetHashCode(); 
     //Get hash code for the index field. 
     int hashKeyIndex = Index.GetHashCode(); 
     //Calculate the hash code for the Key. 
     return hashKeyName^hashKeyIndex; 
    } 
} 
Các vấn đề liên quan