给出两个具有递归结构的对象集合:
Collection1 = [
{
Header: "H1",
Items: [{
Header: "H1.1"
},{
Header: "H1.2"
}]
},
{
Header: "H2",
Items: [{
Header: "H2.1"
}]
}
]
Collection2 = [
{
Header: "H1",
Items: [{
Header: "H1.1",
Items: [{
Header: "H1.1.1"
}]
}]
}
]
我想做一些函数来组合这两个具有比较属性的集合,在本例中为Header
,并且将它们的属性组合在一起,使得结果大致如下:
Result = [
{
Header: "H1",
Items: [{
Header: "H1.1",
Items: [{
Header: "H1.1.1"
}]
},{
Header: "H1.2"
}]
},
{
Header: "H2",
Items: [{
Header: "H2.1"
}]
}
]
如您所见,它会递归检查对象属性,如果存在相似项(在这种情况下,比较Header
属性),它将仅合并两个对象。
我已经尝试过Union()
,Distinct()
等,但似乎无法找到实现此目标的方法。
编辑:合并应该在“相同级别”的基础上进行,因此只有在相同深度级别具有相同标头的项目才应视为相等。
答案 0 :(得分:1)
这是一个为您的商品建模的类:
class Item
{
public string Header { get; set; }
public IEnumerable<Item> Items { get; set; }
}
此递归函数以您描述的方式合并项目:
IEnumerable<Item> Merge(IEnumerable<Item> items)
{
var lookup = items.ToLookup(item => item.Header);
foreach (var grouping in lookup)
{
var childItems = grouping.Aggregate(
new List<Item>(),
(list, item) =>
{
if (item.Items != null)
list.AddRange(item.Items);
return list;
});
yield return new Item
{
Header = grouping.Key,
Items = Merge(childItems)
};
}
}
让我解释一下:
查找就像一个字典,除了每个键的值不是单个Item
而是一个Item
个实例的集合,这些实例都共享相同的键(Header
)。
查找中的每个项目都不是KeyValuePair
,而是IGrouping
,并且通过迭代所有分组,您可以获得该级别上的所有标题。
Aggregate
用于创建包含分组中所有项目的所有子项目的列表。该列表可以包含多个具有相同标题的项目,但这是Merge
设计用于处理的数据。
使用合并子项递归。
要合并两个集合,您需要调用以下函数:
var mergedCollection = Merge(collection1.Concat(collection2));
答案 1 :(得分:1)
您可以执行以下操作...
假设您有一个与此类似的类:
public class Node {
public string Header { get; set; }
public IEnumerable<Node> Items { get; set; }
public Node() {
/* Note that I like to start the collections within the object's construction,
* to avoid issues inside operations that manipulate these collections. */
Items = new Collection<Node>();
}
}
您可以使用IEqualityComparer的递归实现来使用Linq Union的优点。像这样:
public class NodeComparer : IEqualityComparer<Node>
{
public bool Equals(Node me, Node another)
{
if (me.Header == another.Header)
{
me.Items = me.Items.Union(another.Items, new NodeComparer()).ToList();
return true;
}
return false;
}
public int GetHashCode(Node node)
{
return node.Header.GetHashCode();
}
}
主要调用是:
var result = collection1.Union(collection2, new NodeComparer()).ToList();
基本上,这是使用Union方法的比较,考虑节点的标头(通过方法 GetHashCode ),并且对于具有相同标头值的每个节点,都执行相同的过程(通过等于方法)为您的孩子使用,并且这种情况在所有级别上都是连续发生的。
我已经在几种情况下测试了该解决方案,并且看起来效果很好,但是如果仍然存在无法解决的情况,也许这是一个很好的开始。