2011-12-07 98 views
2

我在使用分组时遇到了问题。下面是代码Clojure按多个键分组

(defn combine-by-coords 
    [values] 
    (let [grouped-by-x (group-by :x values)] 
    (persistent! 
    (reduce (fn [res x-val] 
       (assoc! res x-val (group-by :y (x-val grouped-by-x)))) 
      (transient {}) 
      (keys grouped-by-x))))) 

其中地图的值的形式

{:x 754, :y 56, :someKey "zxyf" ....} . 

代码的目的将是组具有相同的x和y值一起映射的。第一I组的x值一起通过使用内置的基团的由功能,这导致

{754 [{....}, {....}]} 

之后,我会通过Y值组中的关键754的阵列。但是,这是我得到一个错误。这似乎并不可能使用密钥754这是我收到的错误:

java.lang.Integer cannot be cast to clojure.lang.IFn 

我也试过(关键字名称)功能,使一键出来的,但是这并未”不管工作。

有没有人知道这个问题的解决方案,或者知道一种方法来重写我的代码?最后,我只需要将具有相同x和y的地图组合在一起。

回答

4

你不能使用像关键字这样的数字。你必须使用get

user=> (5 {5 :x}) 
#<CompilerException java.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IFn (REPL:1)> 
user=> ({5 :x} 5) 
:x 
user=> (get {5 :x} 5) 
:x 

你的情况:与(get grouped-by-x x-val)交换(x-val grouped-by-x)

+0

啊,那更有意义 - 我不知道为什么我无法弄清楚其中组通过调用不工作... –

+1

添加到:注意你得到的错误:'java.lang.Integer不能转换为clojure.lang.IFn' 它告诉你,你正在尝试给我们一个整数作为一个函数。这意味着在某个时候,一个整数被称为一个函数:寻找可能发生的地方:例如(5 {5:x}))关键字和地图实现clojure.lang.IFn接口;你可以通过使用'(supers(class {}))'和'(supers(class:a))'来看到整数不是:'(supers(class 1))'。酷东西,强大的工具。 – Isaac

+0

谢谢你的额外解释@IsaacHodes。我想知道那个'clojure.lang.IFn'错误的意思。 – wvrossem

0

尝试使用#(= (key %) 754)而不是仅将754作为group-by的第一个参数。

问题是group-by的第一个参数需要是一个函数,该函数对要分组的值返回true。关键字可以用作函数,所以这些工作很好,但是当然整数不是函数,所以我们需要编写一个函数来进行比较。

请注意,这允许很大的灵活性,例如

Clojure> (group-by even? (range 10)) 
{true [0 2 4 6 8], false [1 3 5 7 9]} 

UPDATE:看来这不是问题的代码中的问题,但我以为我会离开这个答案的情况下,任何人有类似的问题。

2

或者你可以摆脱X-VAL(密钥)的:

(defn combine-by-coords 
    [values] 
    (let [grouped-by-x (group-by :x values)] 
    (persistent! 
    (reduce (fn [res [x-key vals]] 
       (assoc! res x-key (group-by :y vals))) 
      (transient {}) 
      grouped-by-x)))) 
+0

这样做的技巧,谢谢:) – wvrossem