在Clojure中处理这个序列转换的最佳方法是什么?

时间:2011-11-17 12:27:31

标签: clojure functional-programming

我是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)需要特殊处理某些元素。

感谢您的任何建议。

2 个答案:

答案 0 :(得分: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))))

需要注意几点:

  • start-zero?末尾的问号表示此处需要布尔值。
  • 该代码利用了map对不同长度的序列执行ping函数的事实在最短序列结束时终止。

答案 1 :(得分: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从自身中减去矢量,移动一个位置。