I couldn’t copy your join block, and was not sure whether it were the real thing or a mock-up. So I shook this code out of my sleeve, just in case. You’re welcome!
Yeah... I couldn't believe how many until I read its code. The main thing is that it works for any number of dimensions, not just two; that's why it uses RESHAPE. (I should look into whether the primitive RESHAPE, which was added after I wrote the library, would work.)
(I should also get someone who's better at optimization than I am to redo the library, after he finishes logic programming. :~) )
Yeah, it seems that MAP, especially nested MAPs, aren't as fast as many of the other primitives, so I do my best to avoid it. I try to use COMBINATIONS and COMBINE instead. Here are a couple examples of how to do so (examples taken from problems discussed here: What should this function be named? - (answer group), because it is a recent topic that I tried to figure out how to optimize):
When testing, I found that nested maps (and recursive functions), when given large lists, took longer, lagged, and with extremely large lists actually exceeded the call stack size. However, in this particular instance, I failed to determine a way to use COMBINE, COMBINATIONS, or even RESHAPE (in the hopes of finding out how it compares with @qw23's solution) and @qw23 did come up with a perfectly good solution that avoids MAP.
The reason why MAP is so slow is actually explained here.
Gah, I was with you until that headache-inducing code! (And, btw, how did you make a result pic that isn't a smart pic (loadable into Snap! as code)? I was going to try to solve this problem without such a mess by using DISTRIBUTION OF (one of the options in the portmanteau LENGTH block) but I'm not motivated enough to enter your TABLE list by hand.
Here is the same thing with comments and dependencies such as "all but last of" and "fixed combine". Hopefully it is easier to understand.
EDIT: Here is an even clearer version:
The "fixed combine" block basically just makes sure that the first item is the same rank as the rest of the list when entered. With combine:
In iteration 1, when using a table, the first input will be a 1 dimensional list. However, if your combine then adds another 1 dimensional list to that, then in the next iteration the first input will be a 2 dimensional list. So we need to cover both cases.
With my "fixed" combine:
In iteration 1, when using a table, the first input will be a 2 dimensional list. When the combine then adds another 1 dimensional list to that, then in the next iteration will be a 2 dimensional list once again, so the code does not need to cover both options.
I'm not actually clear what that does, so I would be interested to see what you come up with (if you end up doing it).
which kind of defeats your purpose because I used nested maps!
P.S. If the function you're mapping over the list is simple enough, you can right-click the MAP block and choose "Compile" to speed it up. Then it looks like this:
What it compiles isn't the MAP itself but the mapped function (the first input).