Consider a simple cartesian product:
>>> p = lambda xs, ys: [(x,y) for x in xs for y in ys]
>>> p([1,2],[3,4])
[(1, 3), (1, 4), (2, 3), (2, 4)]
The function that I have in mind is very similar, but it introduces nesting:
>>> q = lambda xs, ys: [[(x,y) for y in ys] for x in xs]
>>> q([1,2],[3,4])
[[(1, 3), (1, 4)], [(2, 3), (2, 4)]]
Of course, that in itself is not very interesting, but we can use it as a higher order function:
>>> q = lambda func: lambda xs, ys: [[func(x,y) for y in ys] for x in xs]
>>> import operator
>>> add = q(operator.add)
>>> add([1],[1])
[[2]]
>>> add([1],[1,2,3])
[[2, 3, 4]]
>>> add([1,2,3],[1])
[[2], [3], [4]]
>>> add([1,2,3],[1,2,3])
[[2, 3, 4], [3, 4, 5], [4, 5, 6]]
That is kind of cool and probably useful in its own right, but we can go even further:
>>> def magic(func):
... def _magic(xs, ys):
... if isinstance(xs, list):
... if isinstance(ys, list):
... return [[_magic(x, y) for y in ys] for x in xs]
... else:
... return [_magic(x, ys) for x in xs]
... else:
... if isinstance(ys, list):
... return [_magic(xs, y) for y in ys]
... else:
... return func(xs, ys)
... return _magic
...
>>> add = magic(operator.add)
>>> add(1,1)
2
>>> add(1,[1,2,3])
[2, 3, 4]
>>> add([1,2,3],1)
[2, 3, 4]
>>> add([1,2],[1,2,3])
[[2, 3, 4], [3, 4, 5]]
>>> add([1,2,3],[1,2])
[[2, 3], [3, 4], [4, 5]]
As you can see, this can be used to map functions over nested lists of values. Might seem a bit esoteric at first, but I have had some concrete uses for it.
Now, the reason I made this thread is because 1) this seems like a pretty general concept, and I would be curious if it is already implemented somewhere, and 2) the magic function could of course be generalized further to take arbitrary numbers of arguments, but I haven't found an elegant way to do it.