2011-08-17 26 views
9

我想知道如果我失去了一些基本的涉及矢量操縱。比方說,我有以下幾點:如何在Clojure中修改一部分矢量?

(def xs [9 10 11 12 13]) 
(def idx [0 2]) 
(def values [1 3]) 

如果我想在Matlab返回矢量[1 10 3 12 13],我會寫xs(idx) = values。 在Clojure中,是否有一種達到此目的的原始方式?現在我正在使用以下功能:

(defn xinto [seq idx val] 
    (apply assoc seq (interleave idx val))) 

謝謝。

+0

我不能提供超出已有建議的代碼。 'assoc' _is_適當的原語,但它希望索引和值單獨傳遞,就像你已經看到的那樣。你可以像你一樣建立一系列索引值對,並使用'apply'或按照amalloy和mikera的建議遞歸地使用'reduce'執行assoc。無論如何,assoc的多索引值版本是遞歸的。我會認爲'減少'選項更習慣。 –

+0

我認爲你的解決方案几乎是最好的。 –

+2

當你想要做的就是專門設置一個索引而不考慮其以前的值時,'apply assoc'和'interleave'可能是最好的選擇。大多數時候,我懷疑你會想做更復雜的事情,然後這個「伎倆」根本就不起作用;這就是爲什麼我建議使用'reduce',這是更一般的。 – amalloy

回答

8

這有點尷尬,因爲你已經將idxvalues分成兩個seq,當它們在概念上是索引到值的映射。所以,如果你允許我你的數據格式的一個小創意修改:

(def x [9 10 11 12 13]) 
(def changes {0 1, 2 3}) 

(defn xinto [v changes] 
    (reduce (fn [acc [k v]] 
      (assoc acc k v)) 
      v 
      changes)) 

(xinto x changes) ;; gets the result you want 

如果你在一些奇怪的方式產生idxvalues,它不是方便他們組合在一起,你可以將它們組合後與(map list idx values)和然後用我的xinto實現。

+0

考慮在這裏使用'transient','assoc!'和'persistent!'。 – seh

+3

@seh呃,我想你可以這樣做,但這似乎不值得付出努力。如果初始矢量或製作的一組變化較小,從瞬態轉換到瞬態所需的時間將超過使用瞬態轉換的收益。 – amalloy

+0

或(zipmap的idx值),而不是(地圖列表idx值) – zmila

2

找不到更好的東西。

在覈心序列函數中有replace,但它適用於值而不是鍵。 所以,

(replace {9 2} x) 

將返回

[2 10 11 12 13] 

如果您打算做數學相關的事情Clojure中,我也建議你看看Incanter。它有很多API來操縱數學數據。

3

我可能會使用reduce此:

(reduce 
    (fn [old [i v]] (assoc old i v)) 
    x 
    (map vector idx values)) 

但是,如果你真的想這樣做了很多(Matlab的風格),那麼我會建議建立一些輔助宏/函數來創建一些種類的矢量操縱的DSL。

+0

我試圖遵循示例代碼,但它似乎缺少原始矢量'x'。爲了清晰起見,我編輯了該示例作爲reduce的三個參數形式。 –