找到两个树结构之间的差异C#

时间:2015-09-09 15:10:56

标签: c# linq tree

我需要一个函数来比较两个不同文件结构之间的差异,并将该差异作为文件结构返回。

我有一个类,“Element”,它有属性ID和Children,ID是一个字符串,Children是Element的集合。

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

我想返回一个结构,告诉我结构A中存在但结构B中缺少哪些元素,如下所示:

Structure Diff
  - Category 1
       - Child Y
  - Category 2

有没有一种简单的方法可以使用LINQ或直接算法(假设树上有多个级别)。

1 个答案:

答案 0 :(得分:1)

示例实现让您入门(仅在一个案例中测试):

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

正如另一个答案中所说,首先获得第二棵树中每个元素的密钥列表更容易,然后根据该列表过滤出第一棵树中的元素。