views:

34

answers:

1

I'm working with a large set of hierarchical taxonomic terms, where each term ("203") has a matching "term203" movie clip on the stage, and am having trouble getting a recursive function to return all of a given term's descendants.

There is a main Dictionary() object with the following nested organization for each term:

{ [object Movie Clip] : { "tid":203, "parent":99, "name":"Culture", selected:false, "otherData":"etc" } }

...where the [object Movie Clip]'s instance name would be "term203". All of these object:subObjectArray items ("terms") are stored in a master taxonomy:Dictionary() object.

I've been trying to make a recursive function (which is in itself already a little above my head) that takes the click.target of a movie clip and returns a new Dictionary() object with all of the children and grandchildren and great grandchildren (etc) of that term, in the same, nested organization described above.

The code below traces the right number of recursive loops, but the returned Dictionary() object only contains the first run's terms (only the immediate children of the requested term).

var taxonomy:Dictionary = new Dictionary();

// ...Term info is loaded into taxonomy from a JSON-style text file)
// ...MOUSE_OVER event listeners are added to each

function revealChildren(hvr:MouseEvent):void {

    trace("Spotlighting " + taxonomy[hvr.target].name + "'s children...");

    for(var key:Object in getAllChildren(taxonomy[hvr.target].tid)) {
        trace("Animating " + taxonomy[key].tid); // Traces only immediate children
        var revealTween = new Tween(key, "alpha", Regular.easeInOut, key.alpha, 1, 1, true);
    }
}

function getAllChildren(origin):Dictionary {

    var children:Dictionary = new Dictionary();

    for(var element:Object in taxonomy) {
        if(taxonomy[element].parent == origin) {
            var subSet = getAllChildren(taxonomy[element].tid);
            children[element] = subSet; // *CAN'T ACCESS 'subSet' PROPERLY*
            trace("Parent = " + origin);
            trace("Matched! Adding " + taxonomy[element].tid + " as key and setting its value to " + subSet); // Traces correct amount of times, one for each descendent
        }
        else {
        }
    }
    return children;
}

I certainly do not claim to be the most efficient AS3 programmer, so I am open to alternative configurations. However, after trying static and nested Arrays, I would prefer to continue using the Dictionary() object as my main pool.

As noted, only the immediate children end up animating in the revealChildren() function. It's mystifying to me then, that in the getAllChildren() function, all of the descendants trace sequentially (well in no particular order) in the output window.

Also I can't get any sort of name or property out of the subSet Object. That could be the problem.

I've only tested it as far as 'two generations,' but it seems that only the first round of calling the function successfully adds those terms to the new Dictionary() object and returns it intact to the animating function.

Too bad dict.filter(getDescendants) won't work. Please help!

+2  A: 

To simplify things, I've added an output parameter called children. This is the Dictionary into which our function will store its results. It has a default value, so you don't need to specify one. In that case, it will create a new instance for itself.

function getAllChildren(origin:*, children:Dictionary = null):Dictionary {
    if (children = null) children = new Dictionary();

    for(var element:* in taxonomy) {
        if(taxonomy[element].parent == origin) {
            children[element] = taxonomy[element];
            getAllChildren(taxonomy[element].tid, children);
        }
    }
    return children;
}

When a child is discovered, it is copied over exactly: children[element] = taxonomy[element];
Next, the function calls itself recursively, supplying it the same output dictionary as it has been using.


Edit:
In response to your comment... Your code originally said this after finding a child named element:

children[element] = getAllChildren(taxonomy[element].tid);

You're making children[element] equal to a Dictionary object here. What you create is a tree structure, mapping MovieClip objects to Dictionary objects containing a similar mapping of its children. Using a for in loop on this structure will only give you the top-level children. It will not recursively traverse the entire tree.

Gunslinger47
Works like a charm - much appreciated! I was unaware I could be that flexible with the function parameters.
atwixtor
For the sake of conceptual understanding, could someone explain why the original recursion was not working as intended?
atwixtor
@atw: I've added an explanation to the end of my answer.
Gunslinger47