2012-03-23 27 views
5

Đối với bài đăng đầu tiên của tôi ở đây, tôi có một câu hỏi liên quan đến so sánh IEnumerable. Tôi có cấu trúc có thể ràng buộc dựa trên logic đếm. Nội dung của các thay đổi IEnumerable theo thời gian và tôi phải tự bắn các sự kiện CollectionChanged.So sánh hai IEnumerable để phát hiện các thay đổi

Tôi có một thuật toán rất ngây thơ cho phép tôi phát hiện các thay đổi đơn giản giữa hai trạng thái của IEnumerable (đơn giản thêm, loại bỏ đơn giản, nhiều bổ sung, nhiều loại bỏ) nhưng nó không phải là rất hiệu quả và không phát hiện tất cả mọi thứ.

Một ví dụ nhanh về những gì tôi cần:

Nhà nước 1 của IEnumerable: A * B * C * D * E

Nhà nước 2 của IEnumerable: A * C * B * D * D1

Đối với ví dụ này, tôi sẽ phải phát hiện

  • Một hoạt động di chuyển: B thay đổi chỉ số 1-2
  • Một Add hoạt động: D1 được chèn vào index 4
  • Một hoạt động remove: E đã được gỡ bỏ

Có một thuật toán để giải quyết vấn đề này một cách hiệu quả càng tốt (O (nLog (n)) sẽ là một khởi đầu tốt)?

Cảm ơn!

+0

B có chuyển từ chỉ mục 1 -> 2 hoặc có C được chuyển từ 2 -> 1 không? hoặc cả hai? –

+0

Nếu trạng thái 1 là 'A B' và trạng thái 2 là' B A A', có hai mục được thêm vào, hoặc thêm một mục và một mục được di chuyển? Nếu 'A' di chuyển, nó di chuyển đến đâu? – Jon

+0

@JamesB: B chuyển từ chỉ mục 1 -> 2 thông tin là đủ! – Sisyphe

Trả lời

1

Đây là uncompiled, mã psuedo chưa được kiểm tra và rút gọn.

Cho một phát hiện động thái duy nhất là đủ Items chỉ có thể di chuyển về phía trước, di chuyển về phía sau sẽ là kết quả của một mục được di chuyển hoặc loại bỏ

ví dụ Nhà nước 1 của IEnumerable: A * B * C * D * E

Nhà nước 2 của IEnumerable: A * D * B * C * D1

quả trong cả B và C di chuyển về phía trước.

enum1pos = -1; 
enum2pos = 0; 
    Value2 = enum2.Next() 
    enum2pos++; 
List<int> SkipList = new SkipList(); 
while(enum1 has values left) 
{ 
    Value1 = enum1.Next() 
    enum1pos++; 
    //Skip over moved items. 
    while (SkipList.Count > 0 && SkipList[0] == enum2.Position) 
    { 
    Value2 = enum2.Next() 
    enum2pos++; 
    } 
    if (Value1 == Value2) 
    Value2 = enum2.Next() 
    enum2pos++; 
    continue; 

    int temp = enum2pos; 
    while(Value1 !=Value and enum2 has more values) 
    { 
    Value2 = enum2.Next(); 
    enum2pos++; 
    } 
    if(Value1 != Value2) 
    ItemDeleted(Value1); 
    else 
    { 
    ItemMoved(Value1, enum2pos); 
    SkipList.Add(enum2pos); 
    } 
    //This is expensive for IEnumerable! 
    enum2.First(); 
    loop temp times 
    enum2.Next(); 
    //if 
} 
while (enum2 has values left) 
{ 
    while (SkipList.Count > 0 && SkipList[0] == enum2.Position) 
    { 
    Value2 = enum2.Next() 
    enum2pos++; 
    } 
    if (enum2 has values left) 
    Added(Value2, enum2pos) 
} 

Kết quả: Hãy so sánh A và A
Tiếp
So sánh B và D
Find B
B Moved -> 2
Thêm 2 đến Bỏ qua Danh sách
Đặt lại Enum2
So sánh C và D
Tìm C
C Đã di chuyển -> 3
Thêm 3 vào Bỏ qua Danh sách
Đặt lại Enum2
Tiếp
Hãy so sánh D và D
Tiếp
Skip (2)
Skip (3)
Hãy so sánh E và D1
Tìm E
Removed (E)
Tiếp
Kết thúc của Enum1 Đã thêm (D1,4)

Tôi nghĩ rằng có một khoản tiết kiệm ở đâu đó nếu enum2pos được quá xa phía sau để xem nếu nó đã được gỡ bỏ và nếu nó đã không thêm một bỏ qua cho vị trí ban đầu của nó trong enum1, điều này sẽ giúp với vị trí của enum2 được thiết lập lại tất cả các thời gian.

+0

Có vẻ như là một lựa chọn tốt. O (n) ở mức tốt nhất, O (n * m) ở mức thấp nhất. Cảm ơn rất nhiều :) – Sisyphe

+0

@Sisyphe, Rất vui được tôi có thể trợ giúp. Đừng quên chấp nhận câu trả lời nếu nó phù hợp với bạn :) –

+0

Chắc chắn, tôi sẽ cố gắng triển khai vào Thứ Hai! Trên thực tế hầu hết các hoạt động IEnumerable sẽ là đơn Add, Single Remove, hoặc Move đơn lẻ. Trong những trường hợp này, thuật toán này sẽ rất hiệu quả. – Sisyphe

1

Nếu bạn thích sử dụng LINQ, đây là một giải pháp đơn giản dựa trên ví dụ của bạn .. Xin lỗi nhưng không chắc chắn về việc thực hiện ..

var a = new List<string>{"A","B","C","D","E"}; 
var b = new List<string>{"A","C","B","D","D1"}; 

var removed = a.Except(b); 
var moved = a.Where(x => b[a.IndexOf(x)] != x && !removed.Contains(x)); 
List<string> newlyInserted = new List<string>(); 
foreach (var item in removed) 
{ 
    //Newly inserted into the list - D1 
    newlyInserted.Add(b[a.IndexOf(item)]); 
    //Index of D1 if required 
    var indexOfNewlyAddedItem = a.IndexOf(item); 
} 

hoặc đơn giản là

var newlyAdded = b.Except(a); 
+0

Cảm ơn câu trả lời của bạn! Hơn nữa, vì tôi phải kích hoạt các sự kiện CollectionChanged, tôi cần danh sách các đối tượng được thêm/xóa cùng với các chỉ mục của chúng để sử dụng Ngoại trừ là không đủ . Dù sao cũng cảm ơn bạn ! – Sisyphe

+0

Không mở rộng điều này vì tôi không biết toàn bộ yêu cầu của bạn, nhưng bạn có thể chỉ cần sử dụng IndexOf() để tìm các chỉ mục của các mục đã xác định. Hy vọng bạn sẽ tìm thấy một câu trả lời tốt hơn cho vấn đề của bạn. – Flowerking

+1

Di chuyển phát hiện truy vấn LINQ - tuyệt vời! Cảm ơn bạn! – selegnasol