在Clojure中是否存在迭代二维序列的“正确”方法? 假设我有一个数字列表列表,比如这个
((1 2 3)
(4 5 6)
(7 8 9))
我希望生成一个新的列表列表,每个数字加1。有没有一种简单的方法在Clojure中执行此操作而不依赖于嵌套映射或循环/重复?我已经能够做到了,但我的解决方案很丑陋,当我重新阅读它们时,我发现它们很难理解。
由于
答案 0 :(得分: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:步行保留类型。
答案 1 :(得分:14)
您始终可以使用列表理解。我发现自己经常使用它们来自命令背景,所以我不知道它是多么惯用。在您的具体情况下,您可以这样做:
(for [my-list my-matrix] (map inc my-list))
答案 2 :(得分:10)
对于二维案例,您可以执行以下操作:
(map #(map inc %) my-two-d-list)
阅读并不算太糟糕:将函数#(map inc %)
应用于列表中的每个元素。
对于高阶情况,你基本上是在谈论树遍历。您需要一个接受树和函数的函数,并将该函数应用于树中的每个节点。您可以在clojure.walk中找到相应的功能。
答案 3 :(得分:5)
Sean和Matt的其他答案都显示了获得正确结果的简明而有效的方法。
但是,您可以对此进行一些重要的扩展:
示例代码:
;; 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))
答案 4 :(得分:5)
自2013年引入core.matrix
以来,现在这是处理多维数组操作的更好方法:
(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
等。答案 5 :(得分:0)
迟来的回答,也许不完全是需要的:你可以尝试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)))))