如何计算树列表中的不同树

时间:2016-07-09 08:21:05

标签: c# linq tree equals

我的树结构如下:

public class TAGNode
{
    public string Val;
    public string Type = "";
    private List<TAGNode> childs;
    public IList<TAGNode> Childs
    {
        get { return childs.AsReadOnly(); }
    }

    public TAGNode AddChild(string val)
    {
        TAGNode tree = new TAGNode(val);
        tree.Parent = this;
        childs.Add(tree);
        return tree;
    }
    public override bool Equals(object obj)
    {
        var t = obj as TAGNode;
        bool eq = Val == t.Val && childs.Count == t.Childs.Count;
        if (eq)
        {
            for (int i = 0; i < childs.Count; i++)
            {
                eq &= childs[i].Equals(t.childs[i]);
            }
        }
        return eq;
    }

}

我有一个这样的树的列表,可以包含重复的树,重复我的意思是它们具有相同的结构和相同的标签。现在我想从这个列表中选择不同的树。我试过了

        etrees = new List<TAGNode>();
        TAGNode test1 = new TAGNode("S");
        test1.AddChild("A").AddChild("B");
        test1.AddChild("C");

        TAGNode test2 = new TAGNode("S");
        test2.AddChild("A").AddChild("B");
        test2.AddChild("C");

        TAGNode test3 = new TAGNode("S");
        test3.AddChild("A");
        test3.AddChild("B");

        etrees.Add(test1);
        etrees.Add(test2);
        etrees.Add(test3);

        var results = etrees.Distinct();

       label1.Text = results.Count() + " unique trees";

这会返回所有树木的数量(3),而我期待2棵不同的树木!我想也许我应该为它实现一个合适的Equals函数,但是在我测试它时并不关心Equals返回的内容!

3 个答案:

答案 0 :(得分:2)

  

我想也许我应该为它实现一个合适的Equals函数

正确。

  

但正如我测试的那样,它并不关心Equals的回报!

因为您必须实现匹配的GetHashCode!它不需要包含Equals中使用的所有项目,在您的情况下Val就足够了。请记住,您只需为可能相等的项返回一个相同的哈希码。具有不同哈希码的项目被视为不相等,并且永远不会使用Equals进行检查。

所以这样的事情应该有效:

public bool Equals(TAGNode other)
{
    if ((object)this == (object)other) return true;
    if ((object)other == null) return false;
    return Val == other.Val && childs.SequenceEqual(other.childs);
}

public override bool Equals(object obj) => Equals(obj as TAGNode);

public override int GetHashCode() => Val?.GetHashCode() ?? 0;

一旦你这样做,你也可以&#34;标记&#34;您的TAGNodeIEquatable<TAGNode>,让默认的相等比较器直接调用Equals(TAGNode other)重载。

答案 1 :(得分:1)

请参阅https://msdn.microsoft.com/en-us/library/bb348436(v=vs.100).aspx

如果要从某些自定义数据类型的对象序列中返回不同的元素,则必须在类中实现IEquatable泛型接口。以下代码示例演示如何在自定义数据类型中实现此接口,并提供GetHashCode和Equals方法。

你需要为TagNode实现IEquatable

答案 2 :(得分:0)

尝试关注GetHashCode。我更新了下面的方法,使其更加强大。害怕原始答案可能无法创造独特的价值观。

        private int GetHashCode(TAGNode node)
        {
            string hash = node.Val;
            foreach(TAGNode child in node.childs)
            {
                hash += GetHashStr(child);
            }
            return hash.GetHashCode();       
        }
        private string GetHashStr(TAGNode node)
        {
            string hash = node.Val;
            foreach (TAGNode child in node.childs)
            {
                hash += ":" + GetHashStr(child);
            }
            return hash;
        }