我已经写了两次相同的函数,分别使用一个列表和一个向量。该函数查找一个元素,然后返回集合中的下一个元素,如果找到的元素在末尾,则自动换行。如果找不到元素,则返回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:我应该正确使用反斜杠还是应该在其位置使用其他内容?
答案 0 :(得分:1)
next-elem-
的第一个版本更好,因为它适用于任何序列。第二版依靠序列来进行有效的索引访问,这很容易导致意外失败并获得性能低下的代码。
建议:将rest
更改为next
。休息已被弃用,在所有情况下下一个都更好。
也避免使用列表。它们是非常具体的数据结构,很少需要。每当需要线性序列时,请先考虑向量。
代码的功能版本:
(defn next-elem- [coll elem]
(->> (concat coll [(first coll)])
(drop-while #(not= % elem))
(second)))