2 个不同类型的列表相等

发布于 10-10 14:15 字数 777 浏览 2 评论 0原文

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

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

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

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

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

Ex为T1和T2,我该如何优化这个问题:

class Device 
{
    string Id;
    string Name;
}

class DeviceInfo
{ 
    string Identifier;
    string FriendlyName;
    DateTime CreateDate;
}

稍后编辑:

解决方案应该涉及我编写的某种相等比较器,并且足够通用。在某些情况下,两个对象具有相同的 Id 但不同的名称,比较就会失败。例如:

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

Let's assume we have 2 collections, at least IEnumerable to power on Linq (also assume .net 4.0):

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

I can define equality between objects of type T1 and T2.

  1. What is the best way (i.e. .net interface and Linq preferred) to verify if the 2 lists are equal (order of elements is not relevant).

  2. How can I optimize this problem if I know that the objects T1 and T2 have an ID

Ex of T1 and T2:

class Device 
{
    string Id;
    string Name;
}

class DeviceInfo
{ 
    string Identifier;
    string FriendlyName;
    DateTime CreateDate;
}

Later edit:

The solution should involve some sort of equality comparer that I write and is generic enough. There may be cases where 2 objects have the same Id but different name, and comparison should then fail. For example:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

云淡风轻2024-10-17 14:15:38

假设 .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);

Assuming .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);

A better solution would also check that foos and bars have the same length, and that none of the elements are null as well. And of course, this example assumes that the collections are already sorted by Id.

Update:

So, here's the "better solution" in all its LINQy detail:

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);
话少情深2024-10-17 14:15:38

你可以这样做:

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 进行推测性转换,以尝试提取标识符。我真的不推荐这个;对于相等比较器来说,比较完全不同类型的对象是一个坏主意。如果让每种类型都实现一个提供标识符的通用接口,那么事情会容易很多。

You could do something like this:

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

If duplicate Ids are not possible, set semantics will come in handy:

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

I would recommend if possible that you declare an IHasId (or similar) interface and get both types to implement it.

EDIT:

In response to your edit, you could write an IEqualityComparer implementation that did what you wanted. It would look really ugly; you would have to do a speculative cast from each argument to DeviceInfo / Device to try and extract an identifier out. I wouldn't really recommend this; it's a bad idea for an equality-comparer to compare objects of completely different types. It would be a lot easier if you got each type to implement a common interface that provided an identifier.

2024-10-17 14:15:38

比较两个字符串列表并不是很复杂。两种基于列表排序的解决方案都具有 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

Comparing 2 lists of strings is not very complicated. Both solutions based on ordering the lists have N log (N) complexity not taking into account the size of the string. The better solution is (pseudocode), complexity is 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
俯瞰星空2024-10-17 14:15:38

尝试以下方法来获取两个不同列表之间的差异:
如果他们有共同财产的话。

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

Try this to get the difference between two different list:
If they have any common property.

 var differentItems = List<Type1>.Select(d => d.Name)
                        .Except(List<Type2>.Select(d => d.Name));
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文