Идиоматически итерируя по 2 (или выше) размерной последовательности в Clojure - PullRequest
11 голосов
/ 11 ноября 2011

Есть ли «правильный» способ перебора двумерной последовательности в Clojure?Предположим, у меня был список списков чисел, например,

 ((1 2 3)
  (4 5 6)
  (7 8 9))

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

Спасибо

Ответы [ 6 ]

18 голосов
/ 11 ноября 2011

То, что вы описываете, является именно тем, для чего 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:Прогулочные консервы типа.

14 голосов
/ 11 ноября 2011

Вы всегда можете просто использовать понимание списка. Я часто использую их, исходя из императивов, поэтому не знаю, насколько это идиоматично. В вашем конкретном случае вы можете сделать:

(for [my-list my-matrix] (map inc my-list))
10 голосов
/ 11 ноября 2011

Для двумерного случая вы можете сделать что-то вроде:

(map #(map inc %) my-two-d-list)

Это не так уж плохо для чтения: примените функцию #(map inc %) к каждому элементу в списке.

Для случая высшего порядка вы в основном говорите о обходе дерева.Вам нужна функция, которая принимает дерево и функцию и применяет эту функцию к каждому узлу в дереве.Вы можете найти функции для этого в clojure.walk .

5 голосов
/ 13 февраля 2014

С момента введения 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:

  • Чистый идиоматический код Clojure
  • Множество универсальных функций манипулирования n-мерным массивом - transpose, shape, reshape, slice, subarray и т. Д.
  • Возможность подключения высокопроизводительных массивов (например, для больших числовых массивов)
5 голосов
/ 11 ноября 2011

Другие ответы Шона и Мэтта показывают краткие и эффективные способы получения правильного результата.

Однако есть несколько важных расширений, которые вы можете сделать для этого:

  • Было бы неплохо разобраться с делом больших размеров
  • Хорошо обернуть функциональность в функцию более высокого порядка

Пример кода:

;; 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))
0 голосов
/ 21 июля 2015

Запоздалый ответ, и, возможно, не совсем то, что нужно: вы можете попробовать flatten . Он вернет последовательность, которую вы можете перебрать:

(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)))))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...