3

Each item looks like this:

public interface IEffect
{
    string Name { get; }
    bool Compute ( );

    List<IEffect> SubEffects { get; set; }
    IEffect ElseIfEffect { get; set; }
}

I want to create a tree-like structure using many instances of these items connected to each other forming a tree-like structure. But later I want to hash each item to a Dictionary, so I thought if I could create a hash value based on where they are on the tree, then I could get unique-enough hash values.

Any ideas on how to do this?

Joan Venge
  • 315,713
  • 212
  • 479
  • 689
  • 3
    Why do you need a hash value? What's wrong with simply using the default object hash function? If this were a complete binary tree, you could map nodes to integer values but with an arbitrary n-ary tree, I don't see a simple way to encode the position to a value. – dfb Feb 10 '11 at 21:29
  • Thanks, to address the need for the hash code is basically this. This tree is gonna be defined at runtime (which is customizable). When a certain action is performed, I want to see which branch/leaf the action currently is and based on that value, look up from a Dictionary what to do next. So based on where in this tree, the same actions will do different things. So for leaf-a, this could be delete, but for leaf-b, it could be remove, for instance. Does it make sense? – Joan Venge Feb 10 '11 at 22:08
  • @Joan: solving it through a HasCode does not make sense. You seem to need a back reference, like an `IEffect parent` property. – H H Feb 10 '11 at 22:11
  • @Henk: Thanks, I was thinking of adding a Parent property for this purpose. But what I am gonna do with that property, if not use it for hashing? – Joan Venge Feb 10 '11 at 22:16
  • I think you could use it "to see which branch/leaf the action currently is". Avoid HashCodes for mutable types (and both your Nodes and Tree appear mutable). – H H Feb 10 '11 at 22:19
  • But wouldn't it the same for 2 child nodes under the same parent? So you can't distinguish them. Yeah these types are mutable. – Joan Venge Feb 10 '11 at 22:23
  • @Joan: Insufficient info to answer this, But I think I could identify the 'Branch' if I had a Parent link. – H H Feb 10 '11 at 22:26
  • And: Do you think it's useful to store items in a Dictionary if the hashCode can change when it gets/looses a neighbour or forebear ? – H H Feb 10 '11 at 22:28
  • No you are right, the Dictionary wouldn't work. You could identify the branch but I need to uniquely identify the node itself, but actually when you mentioned in your replies, I realized I could store a handle to the data I was gonna access from the Dictionary. That should work. – Joan Venge Feb 10 '11 at 22:39

5 Answers5

4

based on where they are on the tree

That information is not part of the node but of the tree. So it would be a very bad idea (defining somethings HashCode on external factors).

Luckily, as @spintheblack points out, there is absolutely no reason to override GethashCode() here.

H H
  • 263,252
  • 30
  • 330
  • 514
2

Copied from my comment per comments :). Why do you need a hash value? What's wrong with simply using the default object hash function? If this were a complete binary tree, you could map nodes to integer values but with an arbitrary n-ary tree, I don't see a simple way to encode the position to a value.

dfb
  • 13,133
  • 2
  • 31
  • 52
2

every item the implements the interface IEffect should override ToString & GetHashCode

ToString shold include unique state of the IEffect properties including the selected value GetHashCode should be ToString().GetHashCode()

and there u have a unique hash for each object based on your object inner data.

Shlomi Komemi
  • 5,445
  • 3
  • 28
  • 41
2

This should do the trick. Warning: Don't override GetHashCode with this method. GetHashCode should not mutate because an objects position in a parent entity has changed. Only use this trick if you have other plans for the hash code. Here is a rough sample of something that should do what you ask. This only shows how you would find the position of the current parent, but you could extend it to walk the tree until it has no parent.

class MyEffect : IEffect
{
    IEffect _owner;
    public MyEffect(IEffect owner) 
    {
        _owner = owner;
    }

    public int GetFunkyHash()
    {
        int hash = this.GetHashCode();
        int index = _owner.IndexOf(item);
        return hash | index.GetHashCode();
    }
}
chilltemp
  • 8,854
  • 8
  • 41
  • 46
  • This is a possible answer, but like others I don't think this is a good idea. Perhaps you could explain why you want to create your own hashing function so that we can understand your needs better. – chilltemp Feb 10 '11 at 21:45
  • Thanks I added more info question's comments. Also can you please tell me what does the line: "int index ..." do? – Joan Venge Feb 10 '11 at 22:11
  • That line of code uses a Linq extension method for find the index of 'this' within the owner's SubEffects collection. – chilltemp Feb 10 '11 at 22:38
  • @chill: what if items are inserted/removed? – H H Feb 10 '11 at 22:44
  • @Henk: The hash value would change if its position in the collection changes. One of the reasons why this shouldn't be used to override GethashCode. – chilltemp Feb 10 '11 at 22:47
  • Thanks but there is no direct method call after SubEffects. Shouldn't it be like _owner.SubEffects.IndexOf, etc? I haven't seen it before by directly using parenthesis right after member name, not method name. – Joan Venge Feb 10 '11 at 22:48
  • Sorry for the confusion.. You're right it should be IndexOf. The collection I was working on in some other code didn't support that method. Actually either method will work, but IndexOf is probably more efficient since it was implemented by the collection and not a generic extension. – chilltemp Feb 10 '11 at 22:53
  • "((item) => item == this)" is an anonymous method. It could have been written similar to this: "private bool IsMatch(IEffect item) { return item == this; }" – chilltemp Feb 10 '11 at 22:59
  • Thanks, what method were you using originally? But either way there was a method after SubEffects, right? – Joan Venge Feb 10 '11 at 22:59
  • The original method wasn't related. I was typing this pseudo-code into a class file that is part of a project I am currently working on. I was using it as was nothing more than an scratch-pad with intellisense. – chilltemp Feb 10 '11 at 23:13
1

Here is how I've done what I think you really need to do. This will walk the entire tree processing effets. No need to link to a parent unless you need to start in the middle of a tree. Of course, this is just my wild interpretation of what you might be trying to do.

public void HandleEffects(IEffect effect)
{
    if(effect.Compute())
        foreach(IEffect child in effect.SubEffects)
            HandleEffects(child);

    else
        HandleEffect(effect.ElseEffect);
}
chilltemp
  • 8,854
  • 8
  • 41
  • 46