以下数据:
(def occurrence-data '(["John" "Artesyn" 1 31.0] ["Mike" "FlexPower" 2 31.0] ["John" "Eaton" 1 31.0]))
我想要一个功能:
(defn visit-numbers
"Produce a map from coordinates to number of customer visits from occurrence records."
[coordinates occurrences]
(let [selector ??? ; a function that would be equivalent to (juxt #(nth % c1) #(nth % c2) ..), where c1, c2, ... are elements of coordinates
]
(group-by selector occurrences)
)
例如,对于coordinates = [1 3]
应该是
(group-by (juxt #(nth % 1) #(nth % 3)) occurrence-data)
我猜应该可以吗?我试图使用一些列表表达但尚未弄清楚。
我的以下实验:
(def selector (list 'juxt '#(nth % 1) '#(nth % 3)))
(group-by selector occurrence-data)
收到错误:
java.lang.ClassCastException: clojure.lang.PersistentList cannot be cast to clojure.lang.IFn
core.clj:6600 clojure.core/group-by[fn]
protocols.clj:143 clojure.core.protocols/fn
protocols.clj:19 clojure.core.protocols/fn[fn]
protocols.clj:31 clojure.core.protocols/seq-reduce
protocols.clj:48 clojure.core.protocols/fn
protocols.clj:13 clojure.core.protocols/fn[fn]
core.clj:6289 clojure.core/reduce
core.clj:6602 clojure.core/group-by
我有两个问题需要解决:
感谢您的指示和帮助!
我也猜测使用宏也可能会这样做吗?
或者我使用过于复杂的方法来实现我的目标?
答案 0 :(得分:4)
只需直接调用juxt来创建你的函数,并定义选择器来保存该函数:
(def selector (juxt #(nth % 1) #(nth % 3)))
要动态创建它,请创建一个函数创建函数:
(defn make-selector [& indexes] (apply juxt (map (fn[i] #(nth % i)) indexes)))
REPL示例:
core> (def occurrence-data '(["John" "Artesyn" 1 31.0] ["Mike" "FlexPower" 2 31.0] ["John" "Eaton" 1 31.0]))
#'core/occurrence-data
core> (def selector (juxt #(nth % 1) #(nth % 3)))
#'core/selector
core> (group-by selector occurrence-data)
{["Artesyn" 31.0] [["John" "Artesyn" 1 31.0]], ["FlexPower" 31.0] [["Mike" "FlexPower" 2 31.0]], ["Eaton" 31.0] [["John" "Eaton" 1 31.0]]}
core> (group-by (make-selector 0 1 2) occurrence-data)
{["John" "Artesyn" 1] [["John" "Artesyn" 1 31.0]], ["Mike" "FlexPower" 2] [["Mike" "FlexPower" 2 31.0]], ["John" "Eaton" 1] [["John" "Eaton" 1 31.0]]}
答案 1 :(得分:2)
这几乎是index
(clojure.set/index occurrence-data [2 3])
;=>
; {{3 31.0, 2 2} #{["Mike" "FlexPower" 2 31.0]},
; {3 31.0, 2 1} #{["John" "Eaton" 1 31.0] ["John" "Artesyn" 1 31.0]}}
例如,您可以看到有两条记录在坐标2和3处共享相同的值,这些值为1和31.0。
如果您想要删除索引并映射到计数,那么
(reduce-kv
(fn [a k v] (conj a {(vals k) (count v)}))
{}
(clojure.set/index occurrence-data [2 3]))
;=> {(31.0 1) 2, (31.0 2) 1}
答案 2 :(得分:1)
定义
(defn group-by-indices [ns coll]
(group-by #(mapv % ns) coll))
然后,例如,
(group-by-indices [1] occurrence-data)
;{["Artesyn"] [["John" "Artesyn" 1 31.0]],
; ["FlexPower"] [["Mike" "FlexPower" 2 31.0]],
; ["Eaton"] [["John" "Eaton" 1 31.0]]}
和
(group-by-indices [2 3] occurrence-data)
;{[1 31.0] [["John" "Artesyn" 1 31.0] ["John" "Eaton" 1 31.0]],
; [2 31.0] [["Mike" "FlexPower" 2 31.0]]}
如果您想保留选择地图,请使用select-keys
代替mapv
。然后我们接近A.Webb's use of clojure.set/index
,这是其他条件相同的选择方法。