Ответ 1
Вы всегда можете просто использовать понимание списка. Я часто использую их, исходя из императивного фона, поэтому я не знаю, насколько он идиоматичен. В вашем конкретном случае вы можете:
(for [my-list my-matrix] (map inc my-list))
Существует ли "правильный" способ итерации по двумерной последовательности в Clojure? Предположим, у меня был список списков чисел, вроде этого
((1 2 3)
(4 5 6)
(7 8 9))
и я хотел создать новый список списков с каждым числом, увеличивающимся на единицу. Есть ли простой способ сделать это в Clojure, не полагаясь на вложенные карты или loop/recurs? Я смог это сделать, но мои решения уродливы, и я нахожу их трудными для понимания, когда перечитываю их.
Спасибо
Вы всегда можете просто использовать понимание списка. Я часто использую их, исходя из императивного фона, поэтому я не знаю, насколько он идиоматичен. В вашем конкретном случае вы можете:
(for [my-list my-matrix] (map inc my-list))
То, что вы описываете, это именно то, что clojure.walk
для:
(def matrix [[1 2 3] [4 5 6] [7 8 9]]) (use 'clojure.walk :only [prewalk]) (prewalk #(if (number? %) (inc %) %) matrix) => [[2 3 4] [5 6 7] [8 9 10]]
Примечание 1: идиоматично использовать векторы вместо круглых скобок для литеральных последовательных коллекций.
Примечание 2: тип сохранения ходьбы.
Для двумерного случая вы можете сделать что-то вроде:
(map #(map inc %) my-two-d-list)
Не так уж плохо читать: применяйте функцию #(map inc %)
к каждому элементу в списке.
Для случая более высокого порядка вы в основном говорите об обходе дерева. Вам нужна функция, которая принимает дерево и функцию, и применяет эту функцию к каждому node в дереве. Вы можете найти функции для этого в clojure.walk.
Другие ответы Шона и Мэтта показывают краткий и эффективный способ получения правильного результата.
Однако есть некоторые важные расширения, которые вы можете сделать для этого:
Пример кода:
;; general higher order function
(defn map-dimensions [n f coll]
(if (= n 1)
(map f coll)
(map #(map-dimensions (dec n) f %) coll)))
;; use partial application to specialise to 2 dimensions
(def map-2d (partial map-dimensions 2))
(map-2d inc
'((1 2 3)
(4 5 6)
(7 8 9)))
=> ((2 3 4) (5 6 7) (8 9 10))
Начиная с введения core.matrix
в 2013 году, это теперь намного лучший способ обработки операций над многомерными массивами:
(use 'clojure.core.matrix)
(def M [[1 2 3]
[4 5 6]
[7 8 9]])
(emap inc M)
=> [[2 3 4 ]
[5 6 7 ]
[8 9 10]]
Преимущества использования core.matrix
:
transpose
, shape
, reshape
, slice
, subarray
и т.д.Запоздалый ответ и, возможно, не совсем то, что нужно: вы можете попробовать flatten. Он вернет seq, который вы можете перебрать:
(flatten '((1 2 3)
(4 5 6)
(7 8 9)))
user=> (1 2 3 4 5 6 7 8 9)
И чтобы увеличить матричные элементы и собрать матрицу:
(partition 3 (map inc (flatten '((1 2 3)
(4 5 6)
(7 8 9)))))