在实现谓词的序列中以惯用方式在两个项目之间插入项目?

时间:2011-10-20 04:20:10

标签: functional-programming clojure

假设我有一个带有两个项的谓词并返回true为false。我想在序列中的每个连续对之间插入一个项目,该序列对谓词返回true。我想出了几个解决方案,但我想知道在Clojure中实现它的惯用方法是什么?

3 个答案:

答案 0 :(得分:4)

我的第一稿似乎是

(defn insert-between [pred inter coll]
  (lazy-seq
   (when-let [s (seq coll)]
     (cons (first s)
           (mapcat (fn [[left right]]
                     (if (pred left right)
                       [inter right]
                       [right]))
                   (partition 2 1 s))))))


user> (insert-between < :less [1 6 7 4 3])
(1 :less 6 :less 7 4 3)

似乎工作,但我很特别 - 以丑陋的方式包装第一个元素,我认为你可以解决这个问题。无论如何,解决方案肯定可以改进。

答案 1 :(得分:3)

这是我的尝试:

(defn interpose-predicated [pred in coll]
  (if (next coll)
    (->> coll
         (partition 2 1)
         (mapcat (comp next #(if (apply pred %) (interpose in %) %)))
         (cons (first coll)))
    coll))

答案 2 :(得分:3)

通常的SO [clojure]比赛提出了最简洁的解决方案。 :-)我通常不会赢,但我在这个过程中学到了很多东西。无论如何,这是我的解决方案:

(defn interpose-p [[a b & _ :as s] d p]
  (when-not (empty? s)
    (if (and (not (nil? b)) (p a b))
      (cons a (cons d (interpose-p (rest s) d p)))
      (cons a (interpose-p (rest s) d p)))))

(interpose-p [1 2 3 2 1 2 3] "," <) 

(1 "," 2 "," 3 2 1 "," 2 "," 3)

更新:即使讨论结束,这里还有一个更新的解决方案,考虑到每个人的评论。假设我对lazy-seq的理解是正确的,这个时间应该是相当的工业强度。它与lazy-seq讨论here有关。

(defn interpose-p
  [pred coll sep]
  (let [f (fn [c]
            (when-let [[a b & _ :as s] (seq c)]
              (if (and b (pred a b))
                (list* a sep (interpose-p pred (rest s) sep))
                (list* a (interpose-p pred (rest s) sep)))))]
    (lazy-seq (f coll))))