在Clojure中旋转一个列表嵌套的矩阵

10

我是Clojure和函数式编程的新手。我不知道如何以函数式的方式处理此问题。

我有以下矩阵:

(def matrix [[\a \b \c]
             [\d \e \f]
             [\g \h \i]])
我想把它转换成这样(逆时针旋转):
((\a \d \g)
 (\b \e \h)
 (\c \f \i ))

我已经处理了这一部分,使元素按正确的顺序排列。如果我能以这种方式收集数据到一个字符串中,那么我就可以使用partition函数进行分割。但是我相当确定doseq不是正确的选择:

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

我曾尝试使用嵌套的map调用,但一直卡在那里。在Clojure中构建字符串的正确方法是什么,或者有没有更好的处理方式?

4个回答

34
你想要实现的听起来像是转置。我建议:
(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))

这个函数会取出三个列表的第一个元素,对它们调用list函数,然后取出第二个元素,再次调用list函数...最终返回所有生成的列表序列。

在ClojureDocs上可以找到更多applymap的示例。


10

我将直接从rosettacode中提取矩阵转置的解决方案:

(vec (apply map vector matrix))

为了了解正在发生什么,请考虑:

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

这将适用于任意矩阵尺寸,但不适合进行大量的数值计算,如果需要进行此类操作,则应考虑使用Clojure中基于Java的矩阵操作库。

5
您可以使用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]]

2
这是一种方法:
(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的列)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接