2

继续我使用 Udacity 的基于 python 的 CS212 并转换为 Clojure 的旅程,我正在尝试编写一个函数:

  1. 返回序列中的所有项目,
  2. 等于序列的最大值,
  3. 使用返回向量的“键”函数

Clojure 的max-key 函数几乎做到了这一点,除了它需要我的键返回一个整数,在这种情况下我不需要——我返回一个向量。通过一些修改,我可以使用 compare 函数来比较我的键控函数返回的向量:

(defn all-max-key
  "Returns a vector of x for which (k x), arbitrated by compare, are greatest."
  ([k x] x)
  ([k x y] (if (= 1 (compare (k x) (k y))) x y))
  ([k x y & more]
     (reduce #(all-max-key k %1 %2) (all-max-key k x y) more)))

现在,问题是这不考虑关系(比较返回 0)。换句话说,我列表中的所有元素都是唯一的,但根据我的键控功能,有些元素可能具有相同的值。在命令式世界中,我可能会遍历列表,跟踪我的最大值,将每个元素与其进行比较,然后在执行过程中附加/替换一个可变列表。

但我觉得必须有一种惯用的、优雅的、实用的方式来做到这一点,而无需求助于循环。我使用 reduce 的尝试都导致将序列与成员元素进行无意义的比较。任何人都可以对此有所了解吗?

4

1 回答 1

2

这将返回最大项的向量:

(defn maximal-key [k x & xs]
  (reduce (fn [ys x]
            (let [c (compare (k x) (k (peek ys)))]
              (cond
                (pos? c) [x]
                (neg? c) ys
                :else    (conj ys x))))
          [x]
          xs))

在 REPL 进行测试:

;; convoluted key function to demonstrate that vector keys are fine
user> (maximal-key #(vector (first %))
                    (list 1 2 3) (list 4 5 6) (list 3 6 8)
                    (list 4 7 9) (list 1 5 9))
[(4 5 6) (4 7 9)]

请注意,它compare可能会返回一个任意正整数以指示其第一个参数大于第二个参数 - 因此pos?代替== 1.

于 2013-01-07T23:59:30.103 回答