首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将clojure分区列表划分为相等的堆

将clojure分区列表划分为相等的堆
EN

Stack Overflow用户
提问于 2014-10-20 09:12:15
回答 4查看 539关注 0票数 1

我正在寻找一种在列表中实现相等堆的方法,该列表可以接受N个元素的列表,并将其拆分为M个堆。任何余数都会逐个添加到每个堆中。我觉得可能已经有什么东西在那里了。

代码语言:javascript
复制
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元素)是所有其他元素中的+/-。

我找到了partion-all,但它没有以我需要的方式处理剩余部分,并且我无法让程序获取生成的列表的最后一个元素并将其放入前面的堆中。

EN

回答 4

Stack Overflow用户

发布于 2014-10-20 10:12:41

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

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

代码语言:javascript
复制
(defn piles [m xs]
  (->> xs
    (map-indexed (fn [i x] [(mod i m) x]))
    (group-by first)
    vals
    (mapv #(mapv peek %))))

请注意,对于足够大的m值,group-by将返回一个散列映射,因此此函数不能保证堆的任何特定顺序(特别是,较短的堆可能先于较高的堆到达)。

REPL中的示例:

代码语言:javascript
复制
(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-based解

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

代码语言:javascript
复制
(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))))

这个函数总是以“自然”的顺序返回堆。

示例:

代码语言:javascript
复制
(piles2 5 [:a :b :c :d :e :f :g :h :i])
;= [[:a :f] [:b :g] [:c :h] [:d :i] [:e]]

保留原始项目顺序的partition-all-based解决方案

作为对评论的回应,这里有一种保持元素原始顺序的方法:

代码语言:javascript
复制
(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)))))

注意:这将返回一个seq序列;您可以使用(mapv vec …)将其转换为向量的向量。

示例:

代码语言:javascript
复制
(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)
票数 5
EN

Stack Overflow用户

发布于 2014-10-20 10:03:25

你可以这样做:

代码语言:javascript
复制
(defn piles [xs m]
  (vals (group-by #(mod % m) xs)))

然后

代码语言:javascript
复制
(piles [1 2 3 4 5 6 7 8 9] 5)

=> (1 6 3 8 5)

票数 2
EN

Stack Overflow用户

发布于 2014-10-21 18:48:05

一个简洁的-尽管缓慢-懒惰的解决方案:

代码语言:javascript
复制
(defn piles [n coll]
  (let [heads (take n (iterate rest coll))]
    (map (partial take-nth n) heads)))

例如

代码语言:javascript
复制
(piles 5 (range 1 10))
;((1 6) (2 7) (3 8) (4 9) (5))
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26457225

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档