Поверните матрицу списка списка в Clojure

Я новичок в Clojure и функциональном программировании в целом. Я не понимаю, как с этим справиться функционально.

У меня есть следующая матрица:

(def matrix [[\a \b \c]
             [\d \e \f]
             [\g \h \i]])

Я хочу преобразовать его в нечто подобное (повернуть против часовой стрелки):

((\a \d \g)
 (\b \e \h)
 (\c \f \i ))

Я взломал этот бит, который дает мне элементы в правильном порядке. Если бы я мог собрать данные в строке таким образом, я мог бы затем разделить ее на раздел. Однако я уверен, что доза является неправильным путем:

(doseq [i [0 1 2]]
  (doseq [row matrix]
    (println (get (vec row) i))))

Я пробовал с вложенными вызовами карты, но продолжаю зацикливаться на этом. Каков правильный способ создания строки в Clojure или справиться с этим еще лучше?

Ответ 1

То, что вы пытаетесь достичь, звучит как transpose. Я предлагаю

(apply map list matrix)
; => ((\a \d \g) (\b \e \h) (\c \f \i))

Что он делает?

(apply map list '((\a \b \c) (\d \e \f) (\g \h \i)))

эквивалентно

(map list '(\a \b \c) '(\d \e \f) '(\g \h \i))

который берет первые элементы каждого из трех списков, список вызовов на них, затем берет на себя второй элемент, список вызовов на них... Возвращает последовательность всех списков, которые были сгенерированы таким образом.

Еще несколько примеров apply и map можно найти на ClojureDocs.

Ответ 2

Взяв преобразование матрицы прямо из rosettacode:

(vec (apply map vector matrix))

Чтобы узнать, что происходит, подумайте:

(map vector [\a \b \c] [\d \e \f] [\g \h \i])

Это будет хорошо работать с произвольными размерами матрицы, хотя это плохо для значительного хрустания числа, для чего вы хотели бы рассмотреть использование библиотеки управления матрицей на основе java из Clojure.

Ответ 3

Вы можете использовать core.matrix, чтобы делать подобные манипуляции с матрицами очень легко. В частности, уже существует функция transpose, которая делает именно то, что вы хотите:

Пример:

(use 'clojure.core.matrix)

(def matrix [[\a \b \c]
             [\d \e \f]
             [\g \h \i]])

(transpose matrix)
=> [[\a \d \g] 
    [\b \e \h] 
    [\c \f \i]]

Ответ 4

Здесь один из способов:

(def transposed-matrix (apply map list matrix))
;=> ((\a \d \g) (\b \e \h) (\c \f \i))

(doseq [row transposed-matrix] 
  (doall (map println row)))

Получает тот же результат, что и ваш оригинал (печать столбцов matrix).