在Clojure中习惯性地迭代2(或更高)维度序列

Joe*_*oel 11 clojure

在Clojure中是否存在迭代二维序列的"正确"方法?假设我有一个数字列表列表,就像这样

 ((1 2 3)
  (4 5 6)
  (7 8 9))
Run Code Online (Sandbox Code Playgroud)

我想生成一个新的列表列表,每个数字加1.有没有一种简单的方法在Clojure中执行此操作而不依赖于嵌套映射或循环/重复?我已经能够做到了,但我的解决方案很难看,当我重新阅读它们时,我发现它们很难理解.

谢谢

Ale*_*art 18

你所描述的恰恰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:步行保留类型.


Sea*_*lan 14

你总是可以使用列表理解.我发现自己经常使用它们来自命令背景,所以我不知道它是多么惯用.在您的具体情况下,您可以:

(for [my-list my-matrix] (map inc my-list))
Run Code Online (Sandbox Code Playgroud)

  • 应该注意,`for`产生一个惰性序列,因此它只在请求值时"迭代". (4认同)

Mat*_*ick 10

对于二维情况,您可以执行以下操作:

(map #(map inc %) my-two-d-list)
Run Code Online (Sandbox Code Playgroud)

这不是一件坏事:将函数#(map inc %)应用于列表中的每个元素.

对于高阶情况,你基本上是在谈论树遍历.您需要一个接受树和函数的函数,并将该函数应用于树中的每个节点.你可以在clojure.walk中找到这个功能.


mik*_*era 5

肖恩和马特的其他答案都显示了获得正确结果的简明而有效的方法.

但是,您可以对此进行一些重要的扩展:

  • 处理更高维度的情况会很好
  • 最好将功能包装在更高阶的功能中

示例代码:

;; 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))
Run Code Online (Sandbox Code Playgroud)


mik*_*era 5

core.matrix2013年推出以来,现在这是处理多维数组操作的更好方法:

(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]]
Run Code Online (Sandbox Code Playgroud)

使用优点core.matrix:

  • 干净,惯用的Clojure代码
  • -通用n维阵列操纵功能很多transpose,shape,reshape,slice,subarray等.
  • 能够插入高性能阵列实现(例如,用于大数值阵列)