简体   繁体   English

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

[英]What's the best way to handle this sequence transformation in Clojure?

I'm new to Clojure, and I've been translating some data manipulation work I did recently as an aid to learning. 我是Clojure的新手,我一直在翻译我最近做的一些数据处理工作,以帮助学习。 I've got a function translation that works fine, and is shorter, but feels much less readable. 我有一个功能翻译,工作正常,而且更短,但感觉更不易读。 Can anyone suggest a more readable and/or more idiomatic way to handle this? 任何人都可以建议更可读和/或更惯用的方式来处理这个问题吗?

In Python: 在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

My attempt at a Clojure translation: 我尝试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))))))

It could be that it's less readable just because of my inexperience with Clojure, but in particular, the trick of prepending an element to the input vector feels to me like it obscures the intention. 可能因为我对Clojure缺乏经验而不太可读,但特别是,将元素添加到输入向量的技巧让我觉得它模糊了意图。 All the solutions I tried which didn't use the prepending trick were much longer and uglier. 我试过的所有没有使用前置技巧的解决方案都要长得多,而且更加丑陋。

Many sequence transformations are incredibly elegant in Clojure, but the ones that I find challenging so far are ones like this one, which a) lend themselves to manipulation by index rather than by element, and/or b) require special handling for certain elements. 在Clojure中,许多序列转换非常优雅,但到目前为止我发现的那些是像这样的,a)适合于通过索引而不是元素进行操作,和/或b)需要对某些元素进行特殊处理。

Thanks for any suggestions. 谢谢你的任何建议。

Idiomatic Clojure tends to manipulate the sequences as a whole, rather than individual elements. 惯用语Clojure倾向于整体操纵序列,而不是单个元素。 You could define create-diff-vector in English as: 你可以用英语定义create-diff-vector

The result is a vector consisting of: 结果是一个由以下内容组成的向量:

  • a zero or the first element of the input, depending of whether start-zero is true or false, respectively; 输入的零或第一个元素,分别取决于start-zero是true还是false; followed by 其次是
  • differences between the input sequence without the first element and the input sequence without the last element. 没有第一个元素的输入序列和没有最后一个元素的输入序列之间的差异。

The second part can be illustrated thusly: for the input (31 41 59 26 53) , we have 第二部分可以这样说明:对于输入(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)

Which, translated to Clojure, becomes remarkably concise: 其中,翻译成Clojure,变得非常简洁:

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

A few points to note: 需要注意的几点:

  • A question mark at the end of start-zero? start-zero?结束start-zero? serves as a hint that a boolean is expected here. 作为一个暗示,这里有一个布尔值。
  • The code exploits the fact that map ping a function over sequences of different lengths terminates upon the end of the shortest sequence. 该代码利用了以下事实:在不同长度的序列上map函数终止于最短序列的末尾。

This implementation would be more idiomatic: 这种实现更加惯用:

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

I first prepend either the first value of the vector or 0 to the input vector. 我首先将向量的第一个值或0添加到输入向量。 Then I use map to subtract the vector from itself, shifted by one position. 然后我使用map从自身中减去向量,移动一个位置。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM