A recursive way to do this (corrected according to the comment - other solutions can also get the IF form).
(defun merge-strings (ab) (concatenate 'string (merge-strings-under ab))) (defun merge-strings-under (ab) (when (and (= (length a) (length b)) (> (length a) 0)) (append (if (string< (aref a 0) (aref b 0)) (list (aref a 0) (aref b 0)) (list (aref b 0) (aref a 0))) (merge-strings-under (subseq a 1) (subseq b 1)))))
Here's an iterative way to do this.
(concatenate 'string (loop for i across "adf" for j across "beg" nconc (list ij)))
Note that they rely on building a string in a list of characters and then vectorizing it (the string is a character vector).
You can also write a more C-esque approach ...
(defun merge-strings-vector (ab) (let ((retstr (make-array (list (+ (length a) (length b))) :element-type 'character))) (labels ((merge-str (abi) (when (and (= (length a) (length b)) (/= i (length a))) (setf (aref retstr (* 2 i)) (aref ai)) (setf (aref retstr (1+ (* 2 i))) (aref bi)) (merge-str ab (1+ i))))) (merge-str ab 0) retstr)))
Note that this - unlike the other 2 - has side effects inside the function. This is also, imo, harder to understand.
All 3 take a different number of cycles to execute on SBCL 56; It seems that in most of my trials each of them takes from 6 to 11 thousand. I'm not sure why.
source share