在Clojure中获取最大值和最小值

3
我正在尝试将SQL查询的最大值和最小值提取到Clojure中,以便我可以对它们进行数学分析,但我不确定为什么会出现错误。我已经在代码中使用了max和min函数来确定这些结果,但我一直收到两个错误,似乎与我使用的:counter关键字有关。
从SQL查询返回的数据在地图中看起来像这样:
    {:date1 "20131007", :data "object1", :counter 1000}
    {:date1 "20131007", :data "object2", :counter 50}
    {:date1 "20131007", :data "object3", :counter 230}

当我使用这段代码时:
    minvalue(min(map(keyword :counter)data2))
    maxvalue(max(map(keyword :counter)data2))
    valrange(- maxvalue minvalue)
    valpc(* (/ valrange 100) 10)
    x(- maxvalue valpc)

我希望将minvalue设置为50,将maxvalue设置为1000,但是我遇到了如下错误:
    java.lang.ClassCastException: clojure.lang.LazySeq cannot be cast to java.lang.Number

如果我从代码中删除map函数并再次运行它,我会得到以下错误:
    java.lang.ClassCastException: clojure.lang.Keyword cannot be cast to java.lang.Number

我非常需要帮助,因为我在这方面完全卡住了(很明显我是Clojure的新手)!谢谢。


1
关于性能的注意事项:如果您需要处理更多的地图,请使用reduce(类似于(reduce min(:counter(第一个地图))(map:counter(其余地图)))),这比apply更有效率。 - noisesmith
2个回答

6
user=> data
[{:data "object1", :date1 "20131007", :counter 1000} {:data "object2", :date1 "20131007", :counter 50} {:data "object3", :date1 "20131007", :counter 230}]

user=> (apply max-key :counter data)
{:data "object1", :date1 "20131007", :counter 1000}

user=> (apply min-key :counter data)
{:data "object2", :date1 "20131007", :counter 50}

谢谢,我刚刚尝试了上面的代码,但仍然出现错误:java.lang.ClassCastException: clojure.lang.LazySeq无法转换为java.lang.Number。我只想要从“:counter”键返回实际的整数值,以便我可以使用实际值进行操作。再次感谢您的帮助! - Paul
1
如果你只想要值,可以使用(apply min (map :counter data))或者(reduce min (map :counter data))。上面的代码和这个代码都是有效的。data应该是一个映射向量。 - defhlt

6

你的代码需要做一些改变:

  • min and max take a variable number of parameters, rather than a collection. Use apply to, well apply the contents of a collection as parameters instead.
  • Clojure naming conventions use - between words
  • Valid calls have to be in a form (basically a list where the first item is callable)
  • No need to use "keyword", keyword is for when you have a string and need an associated keyword. For dragging data out of maps keywords act as functions themselves e.g (:a {:a 1 :b 2}) returns 1.
  • Factored out the commonality in your first two lines

    (def data [{:date1 "20131007", :data "object1", :counter 1000}
               {:date1 "20131007", :data "object2", :counter 50}
               {:date1 "20131007", :data "object3", :counter 230}])
    
    (def counters (map :counter data))      ; => (100 50 230)
    (def min-value (apply min counters))    ; => 50
    (def max-value (apply max counters))    ; => 1000
    (def val-range (- max-value min-value)) ; => 950
    (def val-pc (* (/ val-range 100) 10))   ; => 95
    (def x (- max-value val-pc))            ; => 905
    

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接