Efficient way to walk collections in parallel with doseq (or for)?
clojure
Solution
If you want to avoid the overhead of creating tuples with map, all you can do is write it yourself, as a loop/recur that walks each collection manually. But really, you'll still end up needing to create a tuple so that you can `(apply f args)`, where `args` is the nth item of each collection. You'll save a few cons cells by not making a list of such tuples, but that's all. A lot of the expense of variadic functions like this is calling `apply`, and building the lists to do that with. You can avoid that by writing a 2-arity version of your doseq-sibling, and a 3-arity, and... But the n-arity version will always be slower.
Problem
``` (doseq [e coll1] (myfunc e)) ``` is very fast, if all you care about are side effects. What if I want `myfunc` to take elements from multiple collections "in parallel", i.e. apply `myfunc` to the first elements of each collection, then to all of the second elements, then to all of the third elements, etc.? Note that this is as much a question about the functionality of `for` as `doseq`, but if one wants a sequence as output, `map` will do what's needed, so `for` isn't necessary. ``` (doseq [e1 coll1 e2 coll2] (myfunc e1 e2)) ``` will instead apply `myfunc` to all possible combinations of elements from the two collections. If I know in advance what the elements of the collection will be, I could use a `:when` test to combine only certain elements, but suppose that I don't know that? One solution is to create ntuples to avoid the Cartesian product, but that is time consuming, removing the speed advantage of using `doseq` in the first place: ``` (let [argvecs (map vector coll1 coll2)] ; seq of ntuples of interleaved vals (doseq [args argvecs] (apply myfunc args)))) ``` (This can be about 8X slower than a single-collection `doseq`. See times for `domap1` and `domap17` at the end of this question.)