1

It's probably just the "Friday after 5:00 and I want to go home" effect, but I'm stumped on this problem. I have a recursive iterator method I'll call each:

function canIterate(obj) {
   return (obj && (typeof obj === 'object' || Array.isArray(obj)));
}

function each(obj, onSuccess, recursive) {
    if (canIterate(obj)) {
        Object.keys(obj).forEach(function(key) {
            var val = obj[key];
            if (onSuccess && val && key) {
                var quit = onSuccess(val, key);
                if (false === quit) {
                    return false;
                }
            }
            if (true === recursive) {
                each(val, onSuccess, true);
            }
        });
    }
}

This is quite slow on large sets of data (I'll explain below). As @raganwald explains here, Trampolines are the solution to the problem.. My question is: how do I refactor this recursive function to utilize the trampoline technique?

So I have a polling mechanism to request the current state of a tree, in this case it's a location tree which looks something like:

Hospital Campus Main
    Main Building
        Radiology Department
             Lab 1
             Lab 2
             MRI Lab
                 Machine Cabinets
                     Spare Parts Shelf

The Tree renders in a grid of things that belong to locations, and for each row in the grid that has a location, I need to render the tree setting the root to the location for this row. So if we had:

Part   | Location | Tree
widget   MRI Lab    MRI Lab > Machine Cabinets > Spare Parts Shelf

So never mind that some or all of this could be handled on the server side--I'll optimize performance of the data fetch later.

Is there an efficient way to rewrite my each method to use the Trampoline or CPS style?

hammar
  • 138,522
  • 17
  • 304
  • 385
Christopher
  • 1,723
  • 1
  • 18
  • 31
  • Trampolines are only relevant if the function returns a value and you're doing something with that value. Your function doesn't do anything with the result of the recursive call, so ordinary recursion is no different from trampolining. – Barmar Mar 29 '13 at 22:02
  • One thing that's slowing your function down is that you call `canIterate()` twice as much as necessary. You call it at the top of the function and then when deciding whether to recurse. – Barmar Mar 29 '13 at 22:03
  • Another thing: tail-call elimination is only necessary if you need to handle very deep recursion. This happens when you're using recursion as a substitute for iteration over long lists, for instance (or the factorial example at the site you linked). But you're only recursing for each level in your data structure, and it's not likely to be more than one or two dozen levels. So stack space shouldn't be a concern. Your recursion and iteration should not have performance problems. – Barmar Mar 29 '13 at 22:08
  • @Barmar, duh. That was an obvious fault. Fair enough, re: returning a value. I ripped this out of a larger piece of code for this post. Let's say I am returning and touching a value; perhaps publishing the value to a global event handler--how would I refactor this in that case? I'll have to come back later to instrument my each method according. – Christopher Mar 29 '13 at 22:11
  • @Barmar, unfortunately, not so. These trees are huge, with deeply nested hierarchies. My example is deliberately thin, but it's not unreasonable to have more than 100 levels of depth on small data. – Christopher Mar 29 '13 at 22:13
  • Unless it's thousands deep, I wouldn't worry. – Barmar Mar 29 '13 at 22:14
  • @Barmar please humor me. Even if it offers a negative performance impact on my query, I still want to understand how I would refactor the code. Still, it's always going to be a large data set. Imagine writing an app to inspect for birch beetle infestation in national parks. Your location hierarchy will start with Yellowstone and end with 4th bark segment up from base of tree a42--and inside that hierarchy, each node carries hundreds or thousands of attribute properties. Then suppose that you need to recalculate the "tree" on the fly as inspectors move through the park, scanning trees. – Christopher Mar 30 '13 at 03:29
  • This isn't what SO is for, we don't write code for you. You should attempt to rewrite your code in trampoline style. Then, if it doesn't work, post your attempt and we can help you debug it. – Barmar Mar 30 '13 at 06:18
  • @Barmar, I'm not not asking for you or anyone else to "write my code for me." I'm simply trying to collaborate on the solution to a problem. I think that I know this much so far: i need to refactor the recursion into an iteration which returns a the value to the next iterator, and I need to abstract the inner iteration logic out into its own method. I've see plenty of examples of this for work with factorials, but my use case is just a little different. – Christopher Apr 03 '13 at 09:43
  • I am not sure if you have solved the problem, but may be you could post your question on [Codereview](http://codereview.stackexchange.com/) the have often greate ideas and optimization tips – winner_joiner Apr 05 '13 at 10:59

0 Answers0