Clojure:基于变量动态构造函数?

Clojure:基于变量动态构造函数?,clojure,higher-order-functions,Clojure,Higher Order Functions,有关以下数据: (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 occur

有关以下数据:

(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)
  )
(def selector (juxt #(nth % 1) #(nth % 3)))
(defn make-selector [& indexes] (apply juxt (map (fn[i] #(nth % i)) indexes)))
例如,对于坐标=[13]

应该是

(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
我有两个问题要解决:

  • 如何使选择器成为一个函数
  • 如何动态构造这种基于函数的坐标
  • 谢谢你的指点和帮助

    我还猜测,使用宏也可能做到这一点


    还是我使用了太复杂的方法来实现我的目标?

    只需直接调用juxt来创建您的函数,并定义选择器来保存该函数:

    (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)
      )
    
    (def selector (juxt #(nth % 1) #(nth % 3)))
    
    (defn make-selector [& indexes] (apply juxt (map (fn[i] #(nth % i)) indexes)))
    
    要动态创建,请创建函数创建函数:

    (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)
      )
    
    (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]]}
    

    这几乎是
    索引

    (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}
    
    定义

    然后比如说,

    (group-by-indices [1] occurrence-data)
    ;{["Artesyn"] [["John" "Artesyn" 1 31.0]],
    ; ["FlexPower"] [["Mike" "FlexPower" 2 31.0]],
    ; ["Eaton"] [["John" "Eaton" 1 31.0]]}
    


    如果要保留选择映射,请使用
    select key
    而不是
    mapv
    。然后我们就接近了,也就是说,在其他条件相同的情况下,选择的方法

    我认为OP把函数和宏混在一起了。你不需要引用函数体,你的回答忽略了OP问题的第二部分:如何根据一组坐标动态创建这样一个函数。在Clojure中使用关闭坐标的匿名函数进行此操作非常简单。感谢您向我展示现有的解决方案和优雅的简化!谢谢使用mapv或map和group by来实现目标,非常优雅。