clojure分区列表成相等的堆

时间:2014-10-20 01:12:15

标签: clojure

我正在寻找一种在列表中实现相等堆的方法,该列表可以获取N个元素的列表并将其拆分为M个堆。每个堆中都添加一个剩余部分。我觉得可能已经有了一些东西。

List:  [1 2 3 4 5 6 7 8 9]
M = 5

[[1] [2] [3] [4] [5]]; divided into equal piles with   remainder [6 7 8 9]

[[1 6] [2 7] [3 8] [4 9] [5]]; output

但每一堆中的实际数字我都不在乎。只要(count元素)是所有其他元素的+/-。

我找到了所有人,但它并没有按照我需要的方式处理剩余部分,而且我无法让程序获取生成列表的最后一个元素并将其粘贴到以前的桩。

4 个答案:

答案 0 :(得分:4)

group-by - 基于解决方案(不保证w.r.t.堆排序)

如果列表中的项目可能不是从range获得的连续整数,则可以将Diego函数背后的基本思想应用于索引而不是项目本身:

(defn piles [m xs]
  (->> xs
    (map-indexed (fn [i x] [(mod i m) x]))
    (group-by first)
    vals
    (mapv #(mapv peek %))))

请注意group-by将返回足够大的m值的哈希映射,因此此函数无法保证桩的任何特定排序(特别是较短的桩可能会在较高的桩之前到达)

REPL的例子:

(piles 5 [1 2 3 4 5 6 7 8 9])
;= [[1 6] [2 7] [3 8] [4 9] [5]]
(piles 5 [:a :b :c :d :e :f :g :h :i])
;= [[:a :f] [:b :g] [:c :h] [:d :i] [:e]]
基于

partition-all的解决方案在桩之间交替

或者,您可以使用partition-allmap的自定义版本,该版本仅在所有输入为空时停止:

(defn piles2 [m xs]
  (letfn [(mapv-all [f & colls]
            (loop [colls (map seq colls) ret []]
              (if (every? nil? colls)
                ret
                (recur (map next colls)
                       (conj ret
                         (mapv first (take-while some? colls)))))))]
    (->> xs
      (partition-all m)
      (apply mapv-all vector))))

此函数始终返回" natural"中的桩。顺序。

示例:

(piles2 5 [:a :b :c :d :e :f :g :h :i])
;= [[:a :f] [:b :g] [:c :h] [:d :i] [:e]]
基于

partition-all的解决方案,保留原始订单

在回应评论时,这是一种保持元素原始顺序的方法:

(defn piles3 [m xs]
  (let [cnt (count xs)
        l   (quot cnt m)
        r   (rem cnt m)
        k   (* (inc l) r)]
    (concat
      (partition-all (inc l) (take k xs))
      (partition-all l (drop k xs)))))

NB。这会返回一系列seqs;您可以使用(mapv vec …)将其转换为矢量矢量。

示例:

(piles3 5 (range 32))
;= ((0 1 2 3 4 5 6) (7 8 9 10 11 12 13) (14 15 16 17 18 19) (20 21 22 23 24 25) (26 27 28 29 30 31))
(map count *1)
;= (7 7 6 6 6)

答案 1 :(得分:2)

你可以这样做:

(defn piles [xs m]
  (vals (group-by #(mod % m) xs)))

然后

(piles [1 2 3 4 5 6 7 8 9] 5)

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

答案 2 :(得分:0)

一个简洁 - 虽然缓慢 - 懒惰的解决方案:

(defn piles [n coll]
  (let [heads (take n (iterate rest coll))]
    (map (partial take-nth n) heads)))

例如

(piles 5 (range 1 10))
;((1 6) (2 7) (3 8) (4 9) (5))

答案 3 :(得分:0)

快速渴望的版本:

(defn piles [n coll]
  (loop [ans (vec (repeat n []))
         i 0
         coll coll]
    (if-let [[x & xs] (seq coll)]
      (recur
        (update-in ans [i] conj x)
        (mod (inc i) n)
        xs)
      ans)))

...返回向量向量:

(piles 5 (range 1 10))
;[[1 6] [2 7] [3 8] [4 9] [5]]