2013-01-08 41 views
10

Tôi đang viết một chương trình nhỏ để so sánh hai Danh sách. Nếu các giá trị giống nhau, tôi thêm chúng vào danh sách các dups, nếu chúng khác nhau, tôi thêm chúng vào riêng biệt. Tôi nhận thấy rằng một số giá trị của tôi được thêm vào và một số thì không, và sau khi gỡ lỗi một lúc, tôi không chắc chắn vấn đề là gì. Ai đó có thể làm sáng tỏ một chút ánh sáng? Cảm ơn.So sánh hai Danh sách <int>

 List<int> groupA = new List<int>(); 
     List<int> groupB = new List<int>(); 

     List<int> dups = new List<int>(); 
     List<int> distinct = new List<int>(); 

     groupA.Add(2); 
     groupA.Add(24); 
     groupA.Add(5); 
     groupA.Add(72); 
     groupA.Add(276); 
     groupA.Add(42); 
     groupA.Add(92); 
     groupA.Add(95); 
     groupA.Add(266); 
     groupA.Add(42); 
     groupA.Add(92); 


     groupB.Add(5); 
     groupB.Add(42); 
     groupB.Add(95); 

     groupA.Sort(); 
     groupB.Sort(); 

     for (int a = 0; a < groupA.Count; a++) 
     { 
      for (int b = 0; b < groupB.Count; b++) 
      { 
       groupA[a].CompareTo(groupB[b]); 


       if (groupA[a] == groupB[b]) 
       { 
        dups.Add(groupA[a]); 
        groupA.Remove(groupA[a]); 
        groupB.Remove(groupB[b]); 
       } 

      } 
      distinct.Add(groupA[a]); 
     } 
+0

Bạn có thể đăng kết quả mong đợi không? –

+0

Tôi nghĩ bạn đang xóa nhóm [b] sớm. Bởi vì các công trình của bạn như thế này A1 -> B 1 2 3 4 5 6 7 vv, A2 -> b1 2 3 4 5.Nếu bạn loại bỏ một số từ b, nó sẽ không thể hiển thị trong dups hoặc khác biệt. Nhưng đó chỉ là bản năng của tôi. :) –

+0

Bạn đang xóa các phần tử khỏi danh sách trong khi lặp lại chúng, do đó các điều kiện vòng lặp (dựa trên số phần tử) có thể bị xâm phạm ... – digEmAll

Trả lời

34

tôi sẽ sử dụng IntersectExcept phương pháp:

dups = groupA.Intersect(groupB).ToList(); 
distinct = groupA.Except(groupB).ToList(); 
+1

Giải pháp được bình chọn, tốt đẹp và dễ dàng. – PawelCz

+0

Độ dài của danh sách là quan trọng. var l1 = Danh sách mới () {1, 5, 6}; var l2 = Danh sách mới () {6, 5, 1, 2}; l2.Except (l1) => 2. l1.Except (l2) => không có gì –

8

Khi bạn xóa một mục khỏi danh sách, bạn sẽ chuyển chỉ mục của phần tử còn lại xuống. Về bản chất, bạn đang bỏ qua một số mục bằng cách sử dụng vòng lặp for.
Thử sử dụng vòng lặp while và tăng bộ đếm truy cập theo cách thủ công khi bạn không xóa một mục.

Ví dụ, đoạn mã sau là không chính xác

List<int> nums = new List<int>{2, 4, 6, 7, 8, 10, 11}; 

for (int i = 0; i < nums.Count; i++) 
{ 
    if (nums[i] % 2 == 0) 
    nums.Remove(nums[i]); 
} 

Nếu sẽ trở lại danh sách {4, 7, 10, 11} thay vì chỉ {7, 11}.

Nó sẽ không loại bỏ các giá trị của 4, bởi vì, khi tôi loại bỏ các giá trị của 2, (ví i=0) danh sách nums đi từ

//index 0 1 2 3 4 5 6 
nums = {2, 4, 6, 7, 8, 10, 11} 

để

//index 0 1 2 3 4 5 
nums = {4, 6, 7, 8, 10, 11} 

Các kết thúc vòng lặp , i được tăng lên 1 và mục tiếp theo được tham chiếu là nums[1], không phải là 4 như mong đợi một cách trực giác, nhưng 6. Vì vậy, có hiệu lực giá trị của 4 bị bỏ qua và kiểm tra không được thực hiện.

Bạn nên rất, rất cẩn thận mỗi khi bạn sửa đổi bộ sưu tập bạn đang lặp lại. Ví dụ: tuyên bố foreach sẽ ném một ngoại lệ nếu bạn thậm chí thử điều này. Trong trường hợp này bạn có thể sử dụng một thời gian như

List<int> nums = new List<int>{2, 4, 6, 7, 8, 10, 11}; 

int i = 0; 
while (i < nums.Count) 
{ 
    if (nums[i] % 2 == 0) 
    { 
    nums.Remove(nums[i]) 
    }  
    else 
    { 
    i++; //only increment if you are not removing an item 
     //otherwise re-run the loop for the same value of i 
    } 
} 

của bạn thậm chí có thể ngã ba cho, như

for (int i = 0; i < nums.Count; i++) 
{ 
    if (nums[i] % 2 == 0) 
    { 
    nums.Remove(nums[i]); 
    i--; //decrement the counter, so that it will stay in place 
     //when it is incremented at the end of the loop 
    } 
} 

Hoặc bạn có thể sử dụng LINQ, như thế này:

distinct.AddRange(groupA); 
distinct.AddRange(groupB); 
distinct = distinct.Distinct().ToList(); 

dups.AddRange(groupA); 
dups.AddRange(groupB); 

dups = dups.GroupBy(i => i) 
      .Where(g => g.Count() > 1) 
      .Select(g => g.Key) 
      .ToList(); 

Lưu ý rằng LINQ mã sẽ không thay đổi danh sách groupA và groupB hiện tại của bạn. Nếu bạn chỉ muốn phân biệt chúng, bạn chỉ có thể làm

groupA = groupA.Distinct().ToList(); 
groupB = groupB.Distinct().ToList(); 
+0

Thay thế cả hai vòng lặp bằng một vòng lặp while? – jpavlov

+0

Tôi sẽ để bản triển khai của bạn cho bạn, nhưng tôi đã thêm một ví dụ minh họa nơi mã của bạn bị lỗi và cách khắc phục. – SWeko

4

Bạn có thể dễ dàng làm điều đó với LINQ:

List<int> dups = groupA.Intersect(groupB).ToList(); 
    List<int> distinct = groupA.Except(groupB).ToList(); 

(giả sử tôi đã hiểu chính xác những gì bạn đang cố gắng làm)

Các vấn đề liên quan