2013-01-21 65 views
3

我想寫一個函數adjacents,它返回一個序列的相鄰對的向量。所以(adjacents [1 2 3])將返回[[1 2] [2 3]]如何編寫一個返回相鄰對的列表的Clojure函數?

(defn adjacents [s] 
    (loop [[a b :as remaining] s 
      acc []] 
    (if (empty? b) 
     acc 
     (recur (rest remaining) (conj acc (vector a b)))))) 

我目前的實施適用於字符串的序列,但與整數或字符REPL輸出這個錯誤:

IllegalArgumentException Don't know how to create ISeq from: java.lang.Long clojure.lang.RT.seqFrom (RT.java:494) 

回答

4

這裏的問題是在(adjacents [1 2 3])第一次評估環路,a勢必1b2。然後你問是否bempty?。但empty?對序列起作用,而b不是序列,而是Long,即2。你可以使用此情況下這裏的謂詞是nil?

user=> (defn adjacents [s] 
    #_=> (loop [[a b :as remaining] s acc []] 
    #_=>  (if (nil? b) 
    #_=>  acc 
    #_=>  (recur (rest remaining) (conj acc (vector a b)))))) 
#'user/adjacents 
user=> (adjacents [1 2 3 4 5]) 
[[1 2] [2 3] [3 4] [4 5]] 

但是,正如@amalloy指出,如果你有合法的nil在你的數據,這可能無法得到期望的結果:

user=> (adjacents [1 2 nil 4 5]) 
[[1 2]] 

請參閱他對使用列表的建議實現的評論。

注意,Clojure的partition可以用來做這項工作沒有定義自己的危險:

user=> (partition 2 1 [1 2 3 4 5]) 
((1 2) (2 3) (3 4) (4 5)) 
user=> (partition 2 1 [1 2 nil 4 5]) 
((1 2) (2 nil) (nil 4) (4 5)) 
+2

對'nil?'測試b是災難性的,因爲現在你不能計算'(鄰接關係'[x y nil 5 6 7])'或類似的東西。相反,你需要使用列表,例如'(loop [[x&xs] remaining](如果xs(let [y(first xs)] ...)))''。 – amalloy

+0

確實如此,這只不過是對Levenshtein距離最小的OP代碼進行調整以解決相關問題。 –

0

這是我簡單的回答。一切都變成了一個向量,但它適用於所有的序列。

(defn adjacent-pairs [s] 
    {:pre [(sequential? s)]} 
    (map vector (butlast s) (rest s))) 

測試:

user=> (defn adjacent-pairs [s] (map vector (butlast s) (rest s))) 
#'user/adjacent-pairs 
user=> (adjacent-pairs '(1 2 3 4 5 6)) 
([1 2] [2 3] [3 4] [4 5] [5 6]) 
user=> (adjacent-pairs [1 2 3 4 5 6]) 
([1 2] [2 3] [3 4] [4 5] [5 6]) 
user=> 

這個答案很可能是比上面使用partition一個低效率的,但是。

相關問題