Какой лучший способ справиться с этим преобразованием последовательности в Clojure? - PullRequest
8 голосов
/ 17 ноября 2011

Я новичок в 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, но те, которые я считаю сложными до сих пор, такие, как этот, которыйа) поддаются манипуляции индексом, а не элементом, и / или б) требуют специальной обработки определенных элементов.

Спасибо за любые предложения.

Ответы [ 2 ]

12 голосов
/ 17 ноября 2011

Идиоматическое 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 голос
/ 17 ноября 2011

Эта реализация была бы более идиоматичной:

(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, чтобы вычесть вектор из себя, смещенный на одну позицию.

...