c# - 如何对具有相同子对象列表的对象进行分组?
问题描述
我正在尝试对对象列表进行分组,这些对象具有一个列表属性。使用以下表达式时,它不会将具有列表的对象分组在一起,大概是因为当它检查每个列表的相等性时,它不匹配 - 即使内容相同。
我知道这是问题所在,就好像我停止对列表进行分组一样,代码输出两项而不是三项。
如何调整我的表达方式,以便正确地将前两项(相同的)组合为一个?
public class Item {
public string Id { get; set; }
public string Name { get; set; }
public IEnumerable<ChildItem> Children { get; set; }
}
public class ChildItem {
public string ChildItemName { get; set; }
}
var items = new List<Item> {
new Item {
Id = "00001",
Name = "My Item",
Children = new List<ChildItem> {
new ChildItem { ChildItemName = "string 1" },
new ChildItem { ChildItemName = "string 2" },
}
},
new Item {
Id = "00001",
Name = "My Item",
Children = new List<ChildItem> {
new ChildItem { ChildItemName = "string 1" },
new ChildItem { ChildItemName = "string 2" },
}
},
new Item {
Id = "00002",
Name = "My Second Item",
Children = new List<ChildItem> {
new ChildItem { ChildItemName = "string 3" },
}
}
};
var result =
from c in items
group c by new
{
c.Id,
c.Name,
c.Children,
}
into gcs
select new Item()
{
Id = gcs.Key.Id,
Name = gcs.Key.Name,
Children = gcs.Key.Children
};
解决方案
如果具有相同 Id 的项目具有相同的名称和集合,您可以按 Id 分组,然后取组的第一个项目
IEnumerable<Item> uniqueItems = items
.GroupBy(x => x.Id)
.Select(g => g.First());
您不需要将所有内容都放入组密钥中。
由于根据您的评论,Id
不保证唯一性,因此您必须提供自己对“相等”含义的定义。您可以通过实现自己的相等比较器来做到这一点。
as 单例的实现ChildItem
,因为它将在ItemEqualityComparer.Equals
.
class ChildItemEqualityComparer : IEqualityComparer<ChildItem>
{
public static readonly ChildItemEqualityComparer Instance =
new ChildItemEqualityComparer(); // Create singleton.
private ChildItemEqualityComparer() { } // Hide constructor.
public bool Equals(ChildItem x, ChildItem y) =>
String.Equals(x.ChildItemName, y.ChildItemName);
public int GetHashCode(ChildItem childItem) =>
childItem.ChildItemName?.GetHashCode() ?? 0;
}
的实现Item
:
class ItemEqualityComparer : IEqualityComparer<Item>
{
public bool Equals(Item x, Item y)
{
return x.Id == y.Id && x.Name == y.Name &&
Enumerable.SequenceEqual(x.Children, y.Children,
ChildItemEqualityComparer.Instance);
}
public int GetHashCode(Item item)
{
int hash = 43;
unchecked {
hash = 17 * hash + (item.Id?.GetHashCode() ?? 0);
hash = 17 * hash + (item.Name?.GetHashCode() ?? 0);
foreach (ChildItem childItem in item.Children) {
hash = 17 * hash + ChildItemEqualityComparer.Instance.GetHashCode(childItem);
}
}
return hash;
}
}
和查询:
var result = items.Distinct(new ItemEqualityComparer());
这会产生 2 个项目。
推荐阅读
- json - 无法从 api 调用中获取 Json 数据
- pdf - PDF复制文本问题:奇怪的字符
- r - 当最后一个时间单位只有 1 个观测值时,R 预测中的 ggseasonplot 不显示预测
- python - 我正在使用线程,所以为什么让我的 gui 一直冻结 Oo
- cython - 如何使用任何 pystan 代码解决或抑制警告墙
- php - 在 Laravel 中,Dio 为空的 Flutter 文件上传
- azure - 托管标识是否可用于 API 管理服务和 Azure 函数之间的通信?
- amazon-s3 - 用于 S3 存储桶的 Terraform AWS 可选日志记录
- python - 带有多个 papermill 命令的 Bash 脚本不会因笔记本错误而失败
- reactjs - 模态组件 - onClick 事件