2011-10-20 39 views
5

假设我有一个谓词需要两个项目,并返回false的真假。我想在谓词的返回true的序列中的每个连续对之间插入一个项目。我提出了一些解决方案,但是我想知道在Clojure中以何种惯用方式来实现它的功能?在满足谓词的序列中,在两个项目之间插入项目?

+0

我刚刚交了这4clojure - http://www.4clojure.com/problem/132 –

回答

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)) 
+0

漂亮,简洁,但有许多失败的案例。如果'coll'是空的或无限的?在第一种情况下,你返回'(无)',并且在第二种情况下,你永远花费在计算序列上。 – amalloy

+0

零案件处理不当,但我没有完全想到通过无限序列之一。我现在要修复它。 – mange

+0

啊,我明白了。是的,我错过了无处理代码。有趣的是,它是完全相同的代码导致我注意到的实际问题。我认为你可以将'(nnext(seq coll))'切换为'(next coll)',实际上 - 你现在有太多的'next',导致两个元素的集合在没有测试的情况下被返回。 – amalloy

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) 

似乎工作,但我特别壳体内的第一个元素在一个丑陋的方式我想你可以解决这个问题。无论如何,这个解决方案肯定能够得到改善。

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) 

更新:尽管讨论过,这里是一个更新的解决方案考虑到了大家的意见。假设我对懒惰seq的理解是正确的,这次应该是相当的工业强度。它是从懒惰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)))) 
+0

需要注意的事情:当seq包含'nil's和列表无限长(或者甚至足够长的时间来吹掉堆栈)时,您的解决方案会中断。通过使用内置的序列处理函数('map','partition'等),在后一种情况下,您通常会得到懒惰的好处。 – mange

+0

顺便说一下,这个解决方案有几个容易克服的问题:1 /它不是懒惰的2 /它不是tail-call优化的,但是这两个问题都可以很容易地修复。 –

+2

这两项改进是相互排斥的。你不能懈怠。 – amalloy

相关问题