C# - 如何获得没有标识符的两个列表的补充

时间:2011-02-25 20:50:40

标签: c# linq list

我有两个相同类型的列表。该类型没有标识符或以编程方式区分的任何其他保证方式。

  • 列出A:{1,2,2,3,5,8,8,8}
  • 名单B:{1,3,5,8}

我希望A中的物品不在B中。

  • 期望的结果:{2,2,8,8}

如果类型有标识符,我可以使用如下语句......

var result = listA
      .Where(a => listB.Where(b => b.Id == a.Id).Count() == 0)
      .ToList();

到目前为止,我能做到这一点的唯一方法是使用循环,我将每个项目添加到原始列表中不出现的次数。

foreach (var val in listB.Select(b => b.val).Distinct())
{
  var countA = listA.Where(a => a.val == val).Count();
  var countB = listB.Where(b => b.val == val).Count();
  var item = listA.Where(a => a.val == val).FirstOrDefault();

  for (int i=0; i<countA-countB; i++)
    result.Add(item);
}

有没有更清洁的方法来实现这一目标?

修改: 这是列表中对象的简化版本。它来自一个正在击中另一个系统的Web服务。

public class myObject
{
  public DateTime SomeDate { get; set; }
  public decimal SomeNumber; { get; set; }
  public bool IsSomething { get; set; }
  public string SomeString { get; set; }
}

我收到的数据对于SomeDate / SomeString具有相同的值,并且SomeNumber和IsSomething的值重复。两个对象可能具有相同的属性,但我需要将它们视为不同的对象。

6 个答案:

答案 0 :(得分:9)

试试这个:

var listA = new List<Int32> {1, 2, 2, 3, 5, 8, 8, 8};
var listB = new List<Int32> {1, 3, 5, 8};
var listResult = new List<Int32>(listA);

foreach(var itemB in listB)
{
    listResult.Remove(itemB);
}

答案 1 :(得分:1)

我错过了什么?

class Program
{
    static void Main(string[] args)
    {
        List<int> a = new List<int>();
        a.Add(1);
        a.Add(2);
        a.Add(2);
        a.Add(3);
        a.Add(5);
        a.Add(8);
        a.Add(8);
        a.Add(8);
        List<int> b = new List<int>();
        b.Add(1);
        b.Add(3);
        b.Add(5);
        b.Add(8);

        foreach (int x in b)
            a.Remove(x);

        foreach (int x in a)
            Console.WriteLine(x);

        Console.ReadKey(false);
    }
}

答案 2 :(得分:0)

您可以对两个列表进行排序,然后同时迭代它们。

public IEnumerable<int> GetComplement(IEnumerable<int> a, IEnumerable<int> b)
{
    var listA = a.ToList();
    listA.Sort();
    var listB = b.ToList();
    listB.Sort();
    int i=0,j=0;
    while( i < listA.Count && j < listB.Count )
    {
        if(listA[i] > listB[j]) {yield return listB[j];j++;}
        else if (listA[i] < listB[j]) {yield return listA[i]; i++; }
        else {i++;j++;}
    }
    while(i < listA.Count)
    {
        yield return listA[i];
        i++;
    }
    while(j < listB.Count)
    {
        yield return listB[j];
        j++;
    }
}

我不知道这是否“更干净”,但它应该在大型数据集上更具性能。

答案 3 :(得分:0)

两个列表中的对象是否相同?如果是这样,您可以使用.Where(a => listB.Where(b => b == a).Count() == 0)

或者

.Where(a => !listB.Any(b => b == a))

答案 4 :(得分:0)

这有点令人讨厌,但它可以满足您的需求。虽然不确定性能。

var a = new List<int> { 1, 2, 2, 3, 5, 8, 8, 8 };
var b = new List<int> { 1, 3, 5, 8 };

var c = from x in a.Distinct()
        let a_count = a.Count(el => el == x)
        let b_count = b.Count(el => el == x)

        from val in Enumerable.Repeat (x, a_count - b_count)
        select val;

答案 5 :(得分:0)

为什么不为myObject

实施自己的平等比较器
public class YourTypeEqualityComparer : IEqualityComparer<myObject>
{
    public bool Equals(myObject x, myObject y)

    public int GetHashCode(myObject obj)
}

然后像这样使用它:

var list1 = new List<myObj>();
var list2 = new List<myObj>()
list1.RemoveAll(i => 
    list2.Contains(list1), 
    new YourTypeEqualityComparer()
);

现在list1包含结果。