查找两个树结构 C# 之间的差异
Finding difference between two tree structures C#
我需要一个函数来比较两个不同文件结构之间的差异以及 return 文件结构的差异。
我有一个 class,"Element" 具有属性 ID 和 Children,其中 ID 是一个字符串,而 Children 是元素的集合。
public class Element
{
string ID { get; }
IEnumerable<Element> Children { get; }
}
现在,假设我有以下元素结构:
Structure A Structure B
- Category 1 - Category 1
- Child X - Child X
- Child Y - Child Z
- Category 2
我想要 return 一个结构,它告诉我哪些元素存在于结构 A 中,但在结构 B 中缺失,如下所示:
Structure Diff
- Category 1
- Child Y
- Category 2
是否有使用 LINQ 或直接算法(假设树可以有很多级别)来执行此操作的简单方法。
是的,是的。您可以只比较两个包含文件路径的字符串枚举:
Category 1\
Category 1\Child X
Category 1\Child Y
Category 2\
Category 1\
Category 1\Child X
Category 1\Child Z
有了这两个可枚举项,您可以调用 Enumerable.Except 方法来保留第一个可枚举项中缺少第二个可枚举项的项目。
帮助您入门的实施示例(仅在一种情况下测试):
internal class Program {
private static void Main(string[] args) {
var c1 = new Element[] {
new Element() {ID = "Category 1", Children = new Element[] {
new Element() {ID = "Child X" },
new Element() {ID = "Child Y" }
}},
new Element() {ID = "Category 2",}
};
var c2 = new Element[] {
new Element() {ID = "Category 1", Children = new Element[] {
new Element() {ID = "Child X" },
new Element() {ID = "Child Z" }
}},
};
var keys = new HashSet<string>(GetFlatKeys(c2));
var result = FindDiff(c1, keys).ToArray();
Console.WriteLine(result);
}
private static IEnumerable<Element> FindDiff(Element[] source, HashSet<string> keys, string key = null) {
if (source == null)
yield break;
foreach (var parent in source) {
key += "|" + parent.ID;
parent.Children = FindDiff(parent.Children, keys, key).ToArray();
if (!keys.Contains(key) || (parent.Children != null && parent.Children.Length > 0)) {
yield return parent;
}
}
}
private static IEnumerable<string> GetFlatKeys(IEnumerable<Element> source, string key = null) {
if (source == null)
yield break;
foreach (var parent in source) {
key += "|" + parent.ID;
yield return key;
foreach (var c in GetFlatKeys(parent.Children, key))
yield return c;
}
}
}
如另一个答案所述,首先获取第二棵树中每个元素的简单键列表,然后根据该列表过滤掉第一棵树中的元素会更容易。
我需要一个函数来比较两个不同文件结构之间的差异以及 return 文件结构的差异。
我有一个 class,"Element" 具有属性 ID 和 Children,其中 ID 是一个字符串,而 Children 是元素的集合。
public class Element
{
string ID { get; }
IEnumerable<Element> Children { get; }
}
现在,假设我有以下元素结构:
Structure A Structure B
- Category 1 - Category 1
- Child X - Child X
- Child Y - Child Z
- Category 2
我想要 return 一个结构,它告诉我哪些元素存在于结构 A 中,但在结构 B 中缺失,如下所示:
Structure Diff
- Category 1
- Child Y
- Category 2
是否有使用 LINQ 或直接算法(假设树可以有很多级别)来执行此操作的简单方法。
是的,是的。您可以只比较两个包含文件路径的字符串枚举:
Category 1\
Category 1\Child X
Category 1\Child Y
Category 2\
Category 1\
Category 1\Child X
Category 1\Child Z
有了这两个可枚举项,您可以调用 Enumerable.Except 方法来保留第一个可枚举项中缺少第二个可枚举项的项目。
帮助您入门的实施示例(仅在一种情况下测试):
internal class Program {
private static void Main(string[] args) {
var c1 = new Element[] {
new Element() {ID = "Category 1", Children = new Element[] {
new Element() {ID = "Child X" },
new Element() {ID = "Child Y" }
}},
new Element() {ID = "Category 2",}
};
var c2 = new Element[] {
new Element() {ID = "Category 1", Children = new Element[] {
new Element() {ID = "Child X" },
new Element() {ID = "Child Z" }
}},
};
var keys = new HashSet<string>(GetFlatKeys(c2));
var result = FindDiff(c1, keys).ToArray();
Console.WriteLine(result);
}
private static IEnumerable<Element> FindDiff(Element[] source, HashSet<string> keys, string key = null) {
if (source == null)
yield break;
foreach (var parent in source) {
key += "|" + parent.ID;
parent.Children = FindDiff(parent.Children, keys, key).ToArray();
if (!keys.Contains(key) || (parent.Children != null && parent.Children.Length > 0)) {
yield return parent;
}
}
}
private static IEnumerable<string> GetFlatKeys(IEnumerable<Element> source, string key = null) {
if (source == null)
yield break;
foreach (var parent in source) {
key += "|" + parent.ID;
yield return key;
foreach (var c in GetFlatKeys(parent.Children, key))
yield return c;
}
}
}
如另一个答案所述,首先获取第二棵树中每个元素的简单键列表,然后根据该列表过滤掉第一棵树中的元素会更容易。