两个列表之间的差异

时间:2011-04-12 13:59:57

标签: c#

我有两个填充了CustomsObjects的通用列表。

我需要在第三个列表中检索这两个列表(第一个没有第二个项目的项目)之间的区别。

我在考虑使用.Except()是一个好主意,但我不知道如何使用它。 救命啊!

14 个答案:

答案 0 :(得分:194)

使用Except是正确的方法。如果您的类型覆盖EqualsGetHashCode,或者您只对引用类型相等感兴趣(即,如果它们引用完全相同的对象,则两个引用只是“相等”),您可以使用:

var list3 = list1.Except(list2).ToList();

如果您需要表达一种自定义的平等观念,例如根据ID,您需要实施IEqualityComparer<T>。例如:

public class IdComparer : IEqualityComparer<CustomObject>
{
    public int GetHashCode(CustomObject co)
    {
        if (co == null)
        {
            return 0;
        }
        return co.Id.GetHashCode();
    }

    public bool Equals(CustomObject x1, CustomObject x2)
    {
        if (object.ReferenceEquals(x1, x2))
        {
            return true;
        }
        if (object.ReferenceEquals(x1, null) ||
            object.ReferenceEquals(x2, null))
        {
            return false;
        }
        return x1.Id == x2.Id;
    }
}

然后使用:

var list3 = list1.Except(list2, new IdComparer()).ToList();

请注意,这将删除所有重复的元素。如果您需要保留重复项,最简单的方法是从list2创建一个集合,并使用类似的内容:

var list3 = list1.Where(x => !set2.Contains(x)).ToList();

答案 1 :(得分:52)

你可以这样做:

var result = customlist.Where(p => !otherlist.Any(l => p.someproperty == l.someproperty));

答案 2 :(得分:17)

我认为重要的是要强调 - 使用Except method将返回第一个中没有第二个项目的项目。它不会返回那些第一个没有出现的元素。

var list1 = new List<int> { 1, 2, 3, 4, 5};
var list2 = new List<int> { 3, 4, 5, 6, 7 };

var list3 = list1.Except(list2).ToList(); //list3 contains only 1, 2

但如果你想在两个名单之间找到真正的区别:

第一个没有第二个项目的项目 和没有第一个项目的第二个项目。

您需要使用Except两次:

var list1 = new List<int> { 1, 2, 3, 4, 5};
var list2 = new List<int> { 3, 4, 5, 6, 7 };

var list3 = list1.Except(list2); //list3 contains only 1, 2
var list4 = list2.Except(list1); //list4 contains only 6, 7
var resultList = list3.Concat(list4).ToList(); //resultList contains 1, 2, 6, 7

或者您可以使用HashSet的SymmetricExceptWith方法。但它改变了名为

的集合
var list1 = new List<int> { 1, 2, 3, 4, 5};
var list2 = new List<int> { 3, 4, 5, 6, 7 };

var list1Set = list1.ToHashSet(); //.net framework 4.7.2 and .net core 2.0 and above otherwise new HashSet(list1)
list1Set.SymmetricExceptWith(list2);
var resultList = list1Set.ToList(); //resultList contains 1, 2, 6, 7

答案 3 :(得分:8)

var third = first.Except(second);

(如果您不喜欢引用延迟集合,也可以在ToList()之后调用Except()。)

Except()方法使用默认比较器比较值,如果要比较的值是基本数据类型,例如intstringdecimal等。

否则将通过对象地址进行比较,这可能不是您想要的...在这种情况下,让自定义对象实现IComparable(或实现自定义IEqualityComparer并传递它到Except()方法。

答案 4 :(得分:3)

由于Except扩展方法对两个IEumebles进行操作,因此在我看来它将是一个O(n ^ 2)操作。如果性能是一个问题(如果你的列表很大),我建议从list1创建一个HashSet并使用HashSet的ExceptWith方法。

答案 5 :(得分:2)

如果对于此类任务,以下帮助程序可能很有用:

有 2 个集合,名为 oldValues 的本地集合和名为 newValues 的远程集合 有时您会收到有关远程集合上某些元素已更改的通知,并且您想知道添加、删除和更新了哪些元素。远程集合总是返回它拥有的所有元素。

    public class ChangesTracker<T1, T2>
{
    private readonly IEnumerable<T1> oldValues;
    private readonly IEnumerable<T2> newValues;
    private readonly Func<T1, T2, bool> areEqual;

    public ChangesTracker(IEnumerable<T1> oldValues, IEnumerable<T2> newValues, Func<T1, T2, bool> areEqual)
    {
        this.oldValues = oldValues;
        this.newValues = newValues;
        this.areEqual = areEqual;
    }

    public IEnumerable<T2> AddedItems
    {
        get => newValues.Where(n => oldValues.All(o => !areEqual(o, n)));
    }

    public IEnumerable<T1> RemovedItems
    {
        get => oldValues.Where(n => newValues.All(o => !areEqual(n, o)));
    }

    public IEnumerable<T1> UpdatedItems
    {
        get => oldValues.Where(n => newValues.Any(o => areEqual(n, o)));
    }
}

用法

        [Test]
    public void AddRemoveAndUpdate()
    {
        // Arrange
        var listA = ChangesTrackerMockups.GetAList(10); // ids 1-10
        var listB = ChangesTrackerMockups.GetBList(11)  // ids 1-11
            .Where(b => b.Iddd != 7); // Exclude element means it will be delete
        var changesTracker = new ChangesTracker<A, B>(listA, listB, AreEqual);

        // Assert
        Assert.AreEqual(1, changesTracker.AddedItems.Count()); // b.id = 11
        Assert.AreEqual(1, changesTracker.RemovedItems.Count()); // b.id = 7
        Assert.AreEqual(9, changesTracker.UpdatedItems.Count()); // all a.id == b.iddd
    }

    private bool AreEqual(A a, B b)
    {
        if (a == null && b == null)
            return true;
        if (a == null || b == null)
            return false;
        return a.Id == b.Iddd;
    }

答案 6 :(得分:1)

这是我的解决方法:

File    Severity    Code    Line    Description
variable.cpp    Error   C2280   6   'ssu::Variable::~Variable(void)': attempting to reference a deleted function
variable.cpp    Error   E1790   7   the default constructor of "ssu::GenericArray::Block" cannot be referenced -- it is a deleted function
variable.cpp    Error   E1776   8   function "ssu::Variable::operator=(const ssu::Variable &)" (declared implicitly) cannot be referenced -- it is a deleted function
variable.h      Error   C2079   36  'ssu::Variable::_array' uses undefined class 'ssu::GenericArray'
variable.h      Warning C4624   50  'ssu::Variable': destructor was implicitly defined as deleted
variable.h      Warning C4624   60  'ssu::GenericArray::Block': destructor was implicitly defined as deleted
variable.h      Error   C2079   36  'ssu::Variable::_array' uses undefined class 'ssu::GenericArray'
variable.h      Warning C4624   50  'ssu::Variable': destructor was implicitly defined as deleted
variable.h      Warning C4624   60  'ssu::GenericArray::Block': destructor was implicitly defined as deleted
variable.cpp    Error   C2280   7   'ssu::GenericArray::Block::Block(void)': attempting to reference a deleted function
variable.cpp    Error   C2280   8   'ssu::Variable &ssu::Variable::operator =(const ssu::Variable &)': attempting to reference a deleted function

答案 7 :(得分:0)

有点晚了,但这是我的工作解决方案

 var myBaseProperty = (typeof(BaseClass)).GetProperties();//get base code properties
                    var allProperty = entity.GetProperties()[0].DeclaringType.GetProperties();//get derived class property plus base code as it is derived from it
                    var declaredClassProperties = allProperty.Where(x => !myBaseProperty.Any(l => l.Name == x.Name)).ToList();//get the difference

在上面提到的代码中,我得到了我的基类和派生类列表

之间的属性差异

答案 8 :(得分:0)

{{1}}

答案 9 :(得分:0)

(LINQ)(C#) 本示例说明如何使用 LINQ 比较两个字符串列表,并使用 .Except()输出那些在names1.txt中但不在names2.txt中的行。 / p>

    // Create the IEnumerable data sources.  
    string[] names1 = System.IO.File.ReadAllLines(@"../../../names1.txt");  
    string[] names2 = System.IO.File.ReadAllLines(@"../../../names2.txt");  

    // Create the query. Note that method syntax must be used here.  
    IEnumerable<string> differenceQuery = names1.Except(names2);  

    // Execute the query.  
    Console.WriteLine("The following lines are in names1.txt but not names2.txt");  
    foreach (string s in differenceQuery)  
        Console.WriteLine(s);  

    // Keep the console window open in debug mode.  
    Console.WriteLine("Press any key to exit");  
    Console.ReadKey(); 

答案 10 :(得分:0)

SELECT * FROM deals
WHERE
published = 1 AND 
( expires IS NULL OR DATE(expires) >= today_date)

注意:var list3 = list1.Where(x => !list2.Any(z => z.Id == x.Id)).toList(); 将包含两个列表中都不存在的项目或对象。

答案 11 :(得分:0)

var resultList = checklist.Where(p => myList.All(l => p.value != l.value)).ToList();

答案 12 :(得分:-1)

如果两个列表都实现IEnumerable接口,则可以使用LINQ实现此目的。

list3 = list1.where(i => !list2.contains(i));

答案 13 :(得分:-1)

List<ObjectC> _list_DF_BW_ANB = new List<ObjectC>();    
List<ObjectA> _listA = new List<ObjectA>();
List<ObjectB> _listB = new List<ObjectB>();

foreach (var itemB in _listB )
{     
    var flat = 0;
    foreach(var itemA in _listA )
    {
        if(itemA.ProductId==itemB.ProductId)
        {
            flat = 1;
            break;
        }
    }
    if (flat == 0)
    {
        _list_DF_BW_ANB.Add(itemB);
    }
}