使用clojure中的地图中的键对元素进行分组

时间:2016-09-27 01:56:07

标签: clojure

我有一张表格地图

char

我想将特定范围内的第二个键分组,如

{[3.0 4.0][2.0 7.0][7.0 3.0][4.0 6.0][1.0 4.0][5.0 6.0][4.0 9.0][5.0 11.0][4.0 16.0]}

结果应为

((1-5)(6-10)(11-15)..)

我已经使用peek实现但是失败了。我怎样才能达到这个结果?

1 个答案:

答案 0 :(得分:0)

您混淆了上一个问题的结果。该问题的输出(以及对此问题的输入)是一个类似#{...}的集合,而不是像{...}这样的映射。该集合的每个元素都是长度为2的向量,如[3 4]。

最直接的解决方案是过滤每个搜索范围,如下所示:

(ns clj.core
  (:require [tupelo.core :as t] 
            [datascript.core :as d]
            [clojure.set :as set] ))
(t/refer-tupelo)

(def data
  #{ [3.0 4.0] [2.0 7.0] [7.0 3.0] [4.0 6.0] [1.0 4.0] [5.0 6.0] [4.0 9.0] [5.0 11.0]  [4.0 16.0] } )

(println "1-5:" (filter #(<= 1 (second %) 5) data))

;=> 1-5: ([3.0 4.0] [1.0 4.0] [7.0 3.0])

或者我们可以写一个循环:

(newline)
(doseq [idx (range 5)]
  (let [upper (* (inc idx) 5)
        lower (- upper 4) ]
    (print (format "[%d..%d] => " lower upper))
    (println (filter #(<= 1 (second %) 5) data))))

[1..5]   => ([3.0 4.0] [1.0 4.0] [7.0 3.0])
[6..10]  => ([4.0 9.0] [2.0 7.0] [4.0 6.0] [5.0 6.0])
[11..15] => ([5.0 11.0])
[16..20] => ([4.0 16.0])
[21..25] => ()

请注意,我修复了数据,因此它是一个集合,而不是地图。

您也可以使用group-by

(def result4 (into (sorted-map) 
                   (group-by  #(-> % second dec (quot 5))  data)))
(newline)
(pretty result4)

{0.0 [[3.0 4.0] [1.0 4.0] [7.0 3.0]],
 1.0 [[4.0 9.0] [2.0 7.0] [4.0 6.0] [5.0 6.0]],
 2.0 [[5.0 11.0]],
 3.0 [[4.0 16.0]]}

你可以提取像

这样的值
(newline)
(pp/pprint (vals result4))

([[3.0 4.0] [1.0 4.0] [7.0 3.0]]
 [[4.0 9.0] [2.0 7.0] [4.0 6.0] [5.0 6.0]]
 [[5.0 11.0]]
 [[4.0 16.0]])