2013-03-05 36 views
9

什么会是一个更基于seq整数而不是一个整数分割seq的惯用方法?由整数seq分区

这里是我的实现:

(defn partition-by-seq 
    "Return a lazy sequence of lists with a variable number of items each 
    determined by the n in ncoll. Extra values in coll are dropped." 
    [ncoll coll] 
    (let [partition-coll (mapcat #(repeat % %) ncoll)] 
    (->> coll 
     (map vector partition-coll) 
     (partition-by first) 
     (map (partial map last))))) 

然后(partition-by-seq [2 3 6] (range))产生((0 1) (2 3 4) (5 6 7 8 9 10))

回答

3

上ANKUR的回答的变种,与未成年人除了懒惰和when-let而不是为empty?的明确的测试。

(defn partition-by-seq [parts coll] 
    (lazy-seq 
     (when-let [s (seq parts)] 
     (cons 
      (take (first s) coll) 
      (partition-by-seq (rest s) (nthrest coll (first s))))))) 
+0

我喜欢在这里使用'when-let',因为(cons x nil)只是(x),并且发现比“if”版本更清洁。为什么使用'nthrest'而不是'drop'?看起来内部部分可能是'(when-let [n(first parts)](cons(take n coll)(partition-by-seq(rest parts)(drop n coll))))' – ToBeReplaced 2013-03-05 20:02:41

+0

@ToBeReplaced' nthrest'只是急速下降的'drop',我认为在这种情况下是合适的。再次想到,我不确定它是否重要。事实上,'第一个'可以在'when-let'中移动。 – 2013-03-05 20:22:32

2
(first (reduce (fn [[r l] n] 
       [(conj r (take n l)) (drop n l)]) 
       [[] (range)] 
       [2 3 6])) 

=> [(0 1) (2 3 4) (5 6 7 8 9 10)] 
+0

'reduce'更是不可以偷懒 – Ankur 2013-03-05 16:47:36

+0

人......不会减少一切... – ToBeReplaced 2013-03-05 20:06:56

4

你的实现看起来不错,但也可能是一个更简单的解决方案,它使用简单的递归包裹在lazy-seq(和原来是更有效率)比使用地图和现有的分区,通过在你的情况。

(defn partition-by-seq [ncoll coll] 
    (if (empty? ncoll) 
    '() 
    (let [n (first ncoll)] 
     (cons (take n coll) 
      (lazy-seq (partition-by-seq (rest ncoll) (drop n coll))))))) 
+1

这可以作出甚至懒惰,采取'懒seq'外'cons',这样,即使第一个'(以并不急于评估。 – 2013-03-05 19:13:17