# Map each element of a list over every element of another list

Let's assume I've got two lists: `("A" "B" "C" "D")` and `("+" "-")`. I want to concatenate each element of the first list with every element of the second to get `("A+" "A-" "B+" "B-" ... )`. Is there a proper function to do that, e.g. `(map-each 'concat list1 list2) => list3`?

I came to a solution using nested `mapcar` calls and `reduce` but I think I may be missing something since it doesn't seem to be very uncommon task.

``````(reduce 'append
(mapcar
(lambda (x)
(mapcar
(lambda (y)
(concat x y))
'("+" "-")))
'("A" "B" "C" "D")))
``````

I am not aware of any Elisp built-in function that calls a function on the cartesian product of its list arguments and returns the collected result.

But I like the general `map-cartestian-product` from an answer at stackoverflow quite much.

Since that is a nice general method I've generalized it a bit more to an arbitrary number of sets:

``````(defmacro map-cartesian-product-recursion (fun vars lists)
"Apply (FUN x1 ... xn) for all tuples with xi element of (nth i LISTS)."
(if (car lists)
(let ((x (make-symbol "x")))
`(mapc
(lambda (,x)
,(macroexpand `(map-cartesian-product-recursion ,fun ,(cons x vars) ,(cdr lists))))
,(car lists)))
`(funcall ,fun ,@(nreverse vars))))

(defmacro map-cartesian-product (fun &rest lists)
"Apply (FUN x1 ... xn) for all tuples with xi element of (nth i LISTS)."
`(map-cartesian-product-recursion ,fun nil ,lists))
``````

You can use `map-cartesian-product` for your purpose as follows:

``````(let (ret)
(map-cartesian-product
(lambda (letter sign)
(setq ret (cons (concat letter sign) ret)))
'("A" "B" "C" "D")
'("+" "-"))
(nreverse ret))
``````

The advantage with respect to your proposal is that you do not construct intermediate lists but only one return list.

• Nice answer; I am not sure the explicit call to macroexpand is necessary, it looks like just expanding into a call to `map-cartesian-product-recursion` sould be enough. – coredump Sep 4 '19 at 9:26