Search code examples
clojure

Clojure - Combine two lists by index


How would I combine two lists say '(1 2 3 4) and '(:a :b :c :d) to get (1 :a 2 :b 3 :c 4 :d)

As I can't just do concat as that would add the second list to the end of the first list.

I thought about doing something like

user=> (def a '(1 2 3 4))

user=> (def b '(:a :b :c :d))

user=> (def x (apply conj (second (split-at 1 a)) (nth b 0) (reverse (first (split-at 1 a)))))
(1 :a 2 3 4)

user=> (def y (apply conj (second (split-at 3 x)) (nth b 1) (reverse (first (split-at 3 x)))))
(1 :a 2 :b 3 4)

user=> (def z (apply conj (second (split-at 5 y)) (nth b 2) (reverse (first (split-at 5 y)))))
(1 :a 2 :b 3 :c 4)

user=> (def q (apply conj (second (split-at 7 z)) (nth b 3) (reverse (first (split-at 7 z)))))
(1 :a 2 :b 3 :c 4 :d)

But I think there is a better way

Any help would be much appreciated


Solution

  • An alternative to interleave:

    (mapcat list '(1 2 3 4) '(:a :b :c :d))
    ;;=> (1 :a 2 :b 3 :c 4 :d)
    

    Here mapcat is effectively doing the cat operation after the double map operation has correctly ordered the elements, albeit in list tuples, so '(1 :a) etc.

    More explicitly:

    (apply concat (map list '(1 2 3 4) '(:a :b :c :d))))
    ;;=> (1 :a 2 :b 3 :c 4 :d)
    

    Thus if your first list really is increasing integer values then you don't have to generate them:

    (apply concat (map-indexed list '(:a :b :c :d)))
    ;;=> (0 :a 1 :b 2 :c 3 :d)