2个不同类型列表的平等性

时间:2011-01-04 13:27:48

标签: .net linq interface equality

假设我们有2个集合,至少IEnumerable可以启动Linq(也假设.net 4.0):

List<T1> list1;  
List<T2> list2;

我可以定义T1和T2类型的对象之间的相等性。

  1. 验证2个列表是否相等(元素的顺序不相关)的最佳方法(即.net接口和Linq首选)是什么。

  2. 如果我知道对象T1和T2有ID,我该如何优化此问题

  3. T1和T2之前:

    class Device 
    {
        string Id;
        string Name;
    }
    
    class DeviceInfo
    { 
        string Identifier;
        string FriendlyName;
        DateTime CreateDate;
    }
    

    稍后编辑:

    解决方案应该包含我编写的某种等式比较器,并且足够通用。可能存在2个对象具有相同Id但名称不同的情况,因此比较应该失败。例如:

    static bool AreEqual(Device device, DeviceInfo deviceInfo)
    {
         return device.Id == deviceInfo.Identifier &&
                device.Name == deviceInfo.FriendlyName;
    }
    

4 个答案:

答案 0 :(得分:3)

假设.NET 4.0:

Foo[] foos = new Foo[];
Bar[] bars = new Bar[];

var areDifferent = foos.Zip(bars, (foo, bar) => foo.Id == bar.Id).Any(b => !b);

更好的解决方案还会检查foosbars是否具有相同的长度,并且所有元素都不是null。当然,此示例假定集合已按Id排序。

<强>更新

所以,这是LINQy所有细节中的“更好的解决方案”:

var areDifferent = foos.Count() != bars.Count() ||
                   foos.OrderBy(foo => foo.Id)
                   .Zip(
                       bars.OrderBy(bar => bar.Id),
                       (foo, bar) => foo != null && bar != null && foo.Id == bar.Id)
                   .Any(b => !b);

答案 1 :(得分:2)

你可以这样做:

List<Device> devices = ...
List<DeviceInfo> deviceInfos = ...

var deviceIds = devices.Select(d => d.Id)
                       .OrderBy(id => id);

var deviceInfoIds = deviceInfos.Select(d => d.Identifier)
                               .OrderBy(id => id);

bool areEqual = deviceIds.SequenceEqual(deviceInfoIds);

如果无法复制ID,设置语义将派上用场:

bool areEqual = !devices.Select(d => d.Id)
                        .Except(deviceInfos.Select(d => d.Identifier))
                        .Any();

如果可能的话,我建议您声明一个IHasId(或类似的)接口并获取两种类型来实现它。

修改

为了响应您的编辑,您可以编写一个执行您想要的IEqualityComparer实现。它看起来真的很难看;你必须从每个参数到DeviceInfo / Device进行推测性转换,以尝试提取标识符。我不会真的推荐这个;平等比较器比较完全不同类型的对象是个坏主意。如果您使用每种类型来实现提供标识符的公共接口,那么它将更容易 lot

答案 2 :(得分:0)

比较2个字符串列表并不是很复杂。基于对列表排序的两种解决方案都具有N log(N)复杂度,而不考虑字符串的大小。更好的解决方案是(伪代码),复杂度为N:

create a dictionary<string, int>

foreach element in list1
if element is in dict
 dict[element]++;
else
 dict[element] = 1;

foreach element in list2
if element is in dict
 dict[element]--;
else 
 return NOT_EQUAL;

if dict has only 0 values lists are equal

答案 3 :(得分:0)

试试这个来区分两个不同的列表: 如果他们有任何共同财产。

 var differentItems = List<Type1>.Select(d => d.Name)
                        .Except(List<Type2>.Select(d => d.Name));