我似乎对clojure I / O(或类型系统)有令人讨厌的问题。关键是这个函数,我希望它使用字符串和数字或字符串集合的集合,并返回与数字相关的字符串字典,如
(costlist '( '("Milk" 4) '("Bread" 2) '("Milk")))
给予
{"Milk" 4, "Bread" 2 }
由
定义(defn costlist [lst]
;returns list of costs and appropriate names
(let [snds (filter (fn [x] (not (identical? nil x))) (seconds lst))]
(zipmap
(firsts (take (count snds) (firsts lst)))
(snds lst))))
当使用类型为clojure.lang.PersistentList(我从clojure.lang.LazySeq转换而来)的列表时抛出错误消息
clojure.lang.LazySeq cannot be cast to clojure.lang.IFn
这只会让我感到困惑,因为它的任何论据对我来说似乎都不是LazySeq。
答案 0 :(得分:4)
问题是snds
是懒惰的seq,因此(snds lst)
会抛出错误。 filter
总是返回一个懒惰的序列。
你的功能也太复杂了。尽量简化:
(defn costlist [lst]
(zipmap (map first lst)
(remove nil? (map second lst))))
现在你可以做你想做的事了:
(costlist (list '("Milk" 4) '("Bread" 2) '("Milk")))
我正在使用list
,因为quote
会阻止评估表达式(see ToBeReplaced's answer):
=> '( '("Milk" 4) '("Bread" 2) '("Milk"))
((quote ("Milk" 4)) (quote ("Bread" 2)) (quote ("Milk")))
因此,您应该避免使用quote
来构建列表。
您的解决方案还建议nil
值可能仅出现在列表的末尾。你可以轻松解决它:
(defn costlist [lst]
(->> (filter (comp #{2} count) lst)
(map vec)
(into {})))
所以,现在
(costlist (list '("Milk" 4) '("Milk") '("Bread" 2)))
也会奏效。
答案 1 :(得分:1)
很难给出一个精确的答案,因为你也在使用自己的一些功能(秒和第一)。但是,您应该考虑是否希望costlist
成为您在上面提供的引用形式。
以上相当于:
((quote ("Milk" 4)) (quote ("Bread" 2)) (quote ("Milk")))
我想你想要更像的东西:
(list '("Milk" 4) '("Bread" 2) '("Milk"))
在您的示例中,最外面的引号导致引用内部引号!
答案 2 :(得分:0)
请勿在{{1}}内使用'
。您不希望'()
quote
获得'
。
鉴于您将列表写为:
quote
最优雅的可能是:
'(("Milk" 4)("Bread" 2)("Milk"))
类似于
(def costlist (comp (partial into {})
(partial map vec)
(partial filter second))
不幸的是,这将创建两个lazy-seqs,其中一个会更好。
你可以(def costlist #(into {} (map vec (filter second %))))
给自己一个很酷的减少功能:
(use '(clojure.core [reducers :as r])
让你离开
(def r-fn (comp (r/map vec) (r/filter second)))
感谢(def costlist #(into {} (r-fn %)))
使用into
,您的列表元素只会被分配一次。
由于顺序与哈希映射无关,您也可以使用reduce conj
。然后您的列表将被过滤,并且元素将并行转换为矢量(如果您的列表包含超过512个元素)。
r/fold
根据集合的大小,减速器可能有点太重。对于像你的例子那样的小尺寸,我建议你自己编写缩小功能:
(def constlist #(r/fold (r/monoid conj hash-map) (r-fn %)))