在Clojure中使用2D数组并初始化每个单元格的正确形式

时间:2011-03-03 15:15:11

标签: clojure

(Lisp初学者) 我需要创建一个2D数组,并初始化数组中的每个单元格。使用基于前一单元格中的数据的函数初始化每个单元。因此,将使用函数的结果初始化作为0,1的单元格,该函数使用来自单元格0,0的数据,依此类推。

我想知道设置这样的数据结构的正确的clojure习惯用法是什么。

2 个答案:

答案 0 :(得分:11)

阵列的表示实际上取决于您使用它的需要,而不是初始化它。例如,如果你有密集矩阵,你很可能应该使用这样的向量向量:

[[0, 1, 2, 3, 4],
 [5, 6, 7, 8, 9],
 [9, 8, 7, 6, 5],
 [4, 3, 2, 1, 0],
 [0, 1, 2, 3, 4]]

或单个向量,其中包含原始长度的其他信息:

{:length 5
 :data
 [0, 1, 2, 3, 4, 
 5, 6, 7, 8, 9,
 9, 8, 7, 6, 5, 
 4, 3, 2, 1, 0, 
 0, 1, 2, 3, 4]
}

如果您需要稀疏矩阵,可以使用hash-map s:

{0 {0 0, 4 4},
 2 {2 7},
 3 {0 4, 2 2}}

(因为您的2D阵列很小,并且您根据之前的数据生成下一个值,我相信第一个选项更适合您)。

如果要进行大量特定于矩阵的操作(乘法,分解等),您可能需要使用一些现有的库,如Incanter

至于填写,我的提议是使用transients并存储中期结果,即(对于一维向量):

(defn make-array [initial-value f length]
  (loop [result (transient []), length-left length, interim-value initial-value]
    (if (= length-left 0)
        (persistent! result)
        (recur (conj! result (f interim-value)) (- length-left 1) (f interim-value))))

瞬态将避免在每个新元素上创建新的数据结构,并且临时值将避免从瞬态结构中读取前一个元素。

答案 1 :(得分:2)

我不知道这是不是一种糟糕的技术,但我已经使用散列(或通常是有序的)映射来指定2D“数组”。他们建立起来像这样:

{ [x y] value ... }

由于必须以某种方式指定数组的限制,因此存在缺点。与ffriend的帖子中描述的直接向量呈现相比,它可能非常慢。