代码之家  ›  专栏  ›  技术社区  ›  Post Self

Clojure中包含不可变数据的向量与列表

  •  0
  • Post Self  · 技术社区  · 6 年前

    我写了两次相同的函数,每个函数分别使用一个列表和一个向量。函数查找一个元素并返回集合中的下一个元素,如果找到的元素在末尾,则将其环绕。 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 回复  |  直到 6 年前
        1
  •  1
  •   Niki Tonsky    6 年前

    第一版 next-elem- 更好,因为它可以与任何序列一起工作。第二个版本依靠序列来实现高效的索引访问,这很容易意外地失败并获得低性能的代码。

    建议:改变 rest next . 其余的部分有点被否决了,接下来的部分在所有情况下都更好。

    同时避免使用列表。它们是非常具体的数据结构,很少需要。每当需要线性序列时,首先考虑向量。

    代码的功能版本:

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