2013-01-08 73 views
10

我在写一个小程序来比较两个List。如果值相同,我将它们添加到列表中,如果它们不同,我将它们添加到不同的列表中。我注意到我的一些值被添加,有些不是,经过一段时间的调试后,我不确定问题是什么。有人可以点亮一下吗?谢谢。比较两个列表<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

你能发布预期的结果吗? –

+0

我认为你很快就会删除组[b]。因为你的工作就像这样A1 - > B1 2 3 4 5 6 7等,A2 - > b1 2 3 4 5。如果你从b中删除一个数字,它将无法显示在dups或独特的。但那只是我的本能。 :) –

+0

你正在从列表中删除元素,同时迭代它们,所以循环条件(基于元素编号)可以被破坏... – digEmAll

回答

34

我会用IntersectExcept方法:

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

Upvoted,漂亮和简单的解决方案。 – PawelCz

+0

列表长度很重要。 var l1 =新列表(){1,5,6}; var l2 = new List (){6,5,1,2};除了(l2)=>什么都没有 –

8

当您从列表中删除项目时,会将其余元素的索引向下移动。 实质上,您正在使用for循环跳过一些项目。
尝试使用while循环,并在您未删除项目时手动增加计数器。

例如,下面的代码是不正确

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]); 
} 

如果将返回,而不是仅仅{7, 11}列表{4, 7, 10, 11}

它不会删除的4值,因为,当我删除的2的值,(对于i=0)的nums不胜枚举从

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

环路结束,i递增到1,并且下一个引用的项目是nums[1],这不是直觉上期望的4,而是6.因此实际上4的值被跳过,并且检查不被执行。

每次修改要迭代的集合时,都应该非常小心。例如,如果您尝试这样做,则foreach语句将引发异常。在这种情况下,你可以使用,而像

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

甚至可以用叉子叉了,像

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

另外,您可以使用LINQ,像这样:

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(); 

请注意,LINQ代码不会改变您现有的groupA和groupB列表。如果你只是想区别出它们,你可能只是做

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

用while循环替换两个循环? – jpavlov

+0

我会将你的实现留给你,但我已经添加了一个例子来说明你的代码出错的地方,以及如何解决它。 – SWeko

4

您可以轻松地使用LINQ做到这一点:

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

(假设我正确理解你正在尝试做什么)