векторы против списков с неизменяемыми данными в Clojure - PullRequest
0 голосов
/ 27 января 2019

Я написал одну и ту же функцию дважды, каждый из которых использовал список и вектор соответственно.Функция находит элемент и возвращает следующий в коллекции и оборачивает, если найденный элемент находится в конце.nil возвращается, если элемент не может быть найден.

Версия списка

(def syms '(\< \^ \> \v))

(defn next-elem- [coll elem]
  (loop [coll-rest coll]
    (cond
      (empty? coll-rest) nil
      (= (first coll-rest) elem) (nth coll-rest 1 (first coll))
      :else (recur (rest coll-rest)))))

(defn rotate-left [sym]
  (next-elem- syms sym))

Векторная версия

(def syms [\< \^ \> \v])

(defn next-index- [coll i]
  (let [elem-count (count coll)]
    (cond
      (or (< i 0) (> i elem-count)) -1
      (= i (dec elem-count)) 0
      :else (inc i))))

(defn rotate-left [sym]
  (let [i (.indexOf syms sym)]
    (get syms (next-index- syms i) nil)))

Тесты

(assert (= \< (rotate-left \v)))
(assert (= nil (rotate-left \o)))

Какая версия лучше?Я читал, что списки, как правило, предпочтительнее в функциональном программировании и, по крайней мере, в векторах F # (есть массивы) являются изменяемыми, а это не то, что мне нужно.Работа с индексами также кажется неудобной, но ее легче обернуть, как нефункциональному программисту.

PS: Это одна из первых написанных мной функциональных программ, поэтому она может оказаться неоптимальной.PPS: Правильно ли я использую обратную косую черту или мне нужно что-то другое вместо нее?

1 Ответ

0 голосов
/ 28 января 2019

Первая версия next-elem- лучше, потому что она будет работать с любой последовательностью.Вторая версия полагается на последовательность, чтобы иметь эффективный доступ к индексу, который действительно легко случайно потерпеть неудачу и получить неэффективный код.

Совет: измените rest на next.Остальное не рекомендуется, далее лучше во всех случаях.

Также избегайте использования списков.Это очень специфическая структура данных, редко необходимая.Всякий раз, когда вам нужна линейная последовательность, сначала рассмотрите вектор.

Функциональная версия вашего кода:

(defn next-elem- [coll elem]
  (->> (concat coll [(first coll)])
       (drop-while #(not= % elem))
       (second)))
...