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
         (lambda (x)
             (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")))
          (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)
   (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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.