2011-11-17 75 views
8

我是Clojure的新手,我一直在翻譯一些我最近做過的數據操作工作,以幫助學習。我有一個函數翻譯工作正常,並且更短,但感覺更不可讀。任何人都可以提出更可讀和/或更習慣的方式來處理這個問題嗎?在Clojure中處理這個序列轉換的最佳方式是什麼?

在Python:

def createDifferenceVector(v,startWithZero=True): 
    deltas = [] 
    for i in range(len(v)): 
     if i == 0: 
      if startWithZero: 
       deltas.append(0.0) 
      else: 
       deltas.append(v[0]) 
     else: 
      deltas.append(v[i] - v[i-1]) 
    return deltas 

我在Clojure的翻譯嘗試:

(defn create-diff-vector [v start-zero] 
    (let [ext-v (if start-zero 
       (cons (first v) v) 
       (cons 0 v))] 
    (for [i (range 1 (count ext-v))] 
     (- (nth ext-v i) (nth ext-v (- i 1)))))) 

這可能是因爲它的可讀性只是因爲我的經驗不足使用Clojure的,但特別的訣竅對輸入向量預先添加一個元素讓我感覺像是模糊了這個意圖。我嘗試過的所有解決方案都沒有使用預先設定的技巧,這些解決方案的時間更長,更醜陋。在Clojure中,許多序列轉換令人難以置信的優雅,但到目前爲止,我發現挑戰的是像這樣的一個,它們a)適合於通過索引而不是元素來操作,和/或b)需要特殊處理對於某些元素。

感謝您的任何建議。

回答

12

習慣性的Clojure傾向於操作整個序列,而不是單個元素。你可以在英語中定義create-diff-vector爲:

結果是向量包括:

  • 零或取決於的start-zero是否是真還是假,分別是輸入的第一個元素,;其次是
  • 輸入序列沒有第一個元素和輸入序列沒有最後一個元素之間的差異。

第二部分可正是如此來說明:爲輸入(31 41 59 26 53),我們有

 
    input without the first element: (41 59 26 53) 
- input without the last element: (31 41 59 26) 
=================================================== 
    result:       (10 18 -33 27) 

其中,轉換爲Clojure中,變得非常簡潔:

(defn diff-vector [v start-zero?] 
    (into [(if start-zero? 0 (first v))] 
    (map - (rest v) v)))) 

有幾點要注意:

  • 01號結尾的問號作爲提示,預計布爾值在這裏。
  • 該代碼利用了這樣一個事實,即map在不同長度的序列上ping一個函數會在最短序列結束時終止。
+2

非常酷。我總是忘記我可以這樣做'(map foo x(rest x))'thing - 我通常到達'partition',而不是像'[for [[ab](partition 2 1 v)]( - ba) )'。地圖更好,謝謝提醒。 – amalloy

+0

謝謝。這是一個非常明確的解釋,並且以更多更優雅的方式表達它。這肯定會讓我花一些時間來圍繞着Clojure的思維方式,但我已經看到了收益。 – eggsyntax

+0

嘿。五年後,現在是一名專業的Clojure /腳本開發人員,我恰好碰巧遇到了這個問題。獨立撰寫了一個解決方案,最後幾乎與你的一樣,逐字逐句地相同,@丹尼爾。感謝您幫助我走上正確的道路 – eggsyntax

1

此實現會更慣用:

(defn create-diff-vector [v start-with-zero?] 
    (let [v (cons (if start-with-zero? (first v) 0) v)] 
     (map - (rest v) v))) 

予先在前面加上任一所述載體的第一值或0至輸入矢量。然後我用map從它自身中減去矢量,移動一個位置。

相關問題