Clojure 哈希映射未显示为哈希映射
克洛朱尔的新朋友。尝试用java背景解决以下问题。我需要将表转换为一个散列图,该散列图将产品映射到所有销售该产品的城市。所以输出应该是Clojure 哈希映射未显示为哈希映射,clojure,Clojure,克洛朱尔的新朋友。尝试用java背景解决以下问题。我需要将表转换为一个散列图,该散列图将产品映射到所有销售该产品的城市。所以输出应该是 {"Pencil": ("Oshawa" "Toronto") "Bread": ("Ottawa" "Oshawa" "Toronto")} (def table [ {:product "Pencil" :city "Toronto" :year "2010" :sales "2653.0
{"Pencil": ("Oshawa" "Toronto")
"Bread": ("Ottawa" "Oshawa" "Toronto")}
(def table [
{:product "Pencil"
:city "Toronto"
:year "2010"
:sales "2653.00"}
{:product "Pencil"
:city "Oshawa"
:year "2010"
:sales "525.00"}
{:product "Bread"
:city "Toronto"
:year "2010"
:sales "136,264.00"}
{:product "Bread"
:city "Oshawa"
:year "nil"
:sales "242,634.00"}
{:product "Bread"
:city "Ottawa"
:year "2011"
:sales "426,164.00"}])
这就是我目前所拥有的。我将此代码写入repl
(let [product-cities {}]
(for [row table]
(if (= (contains? product-cities (keyword (row :product))) true)
(println "YAMON") ;;To do after. Add city to product if statement is true
(into product-cities {(keyword (row :product)) (str (row :city))}))))
然而,结果如下:
({:Pencil "Toronto"}
{:Pencil "Oshawa"}
{:Bread "Toronto"}
{:Bread "Oshawa"}
{:Bread "Ottawa"})
我的if语句总是返回false。我看到许多散列映射周围有半圆括号。我不明白为什么它不返回一个hashmap,为什么有很多hashmap?谢谢
编辑:
问题2:
将表转换为将产品映射到销售额最高的城市的哈希映射。例如,输出应如下所示:
{"Pencil": "Toronto"
"Bread": "Ottawa"}
我认为需要一种不同于建立价值观的战略,但以下是我的想法:
(reduce (fn [product-cities {:keys [product city sales]}]
(update-in product-cities [product] (fnil conj []) {(keyword city) sales}))
{}
table)
这将产生以下输出:
{"Bread"
[{:Toronto "136,264.00"}
{:Oshawa "242,634.00"}
{:Ottawa "426,164.00"}],
"Pencil"
[{:Toronto "2653.00"}
{:Oshawa "525.00"}]}
然后我可以再次使用reduce函数,但只添加具有最大销售额的城市。我认为这不是最有效的方法 您需要逐一查看该表并累积(
conj
)产品下的城市:
(reduce
(fn [acc {:keys [product city]}]
(update acc product conj city))
{}
table)
;; => {"Pencil" ("Oshawa" "Toronto"), "Bread" ("Ottawa" "Oshawa" "Toronto")}
使用更新函数(conj
,在本例中)可能有点棘手,因此这里是update
的另一种形式:
(update acc product (fn [cities]
(conj cities city)))
我不是从{}
开始的,而是:
{"Pencil" []
"Bread" []}
这可能更容易看出,对于表中的每个条目,update
通过将最新的城市放在序列的末尾(这就是conj
所做的)来更新产品密钥(“铅笔”或“面包”)。当它工作时,我只是用{}
替换,使用update
将插入一个新的键(如果没有)
我认为的具有生成性。它以一个序列作为输入,并在每一步生成一个新的事物-因此,你最终会得到一个新事物序列。生成时不可能更新产品城市
reduce
对于您想要做的事情更有用,因为您得到了一个“累加器”,可以在每个步骤中稍微修改它。实际上,您每次都在通过修改传入的“累加器”来创建一个新的“累加器”,所以实际上您根本没有修改任何东西:Clojure是一种函数式语言,它的全部内容都是创建新事物 您需要逐一查看该表并累积(conj
)产品下的城市:
(reduce
(fn [acc {:keys [product city]}]
(update acc product conj city))
{}
table)
;; => {"Pencil" ("Oshawa" "Toronto"), "Bread" ("Ottawa" "Oshawa" "Toronto")}
使用更新函数(conj
,在本例中)可能有点棘手,因此这里是update
的另一种形式:
(update acc product (fn [cities]
(conj cities city)))
我不是从{}
开始的,而是:
{"Pencil" []
"Bread" []}
这可能更容易看出,对于表中的每个条目,update
通过将最新的城市放在序列的末尾(这就是conj
所做的)来更新产品密钥(“铅笔”或“面包”)。当它工作时,我只是用{}
替换,使用update
将插入一个新的键(如果没有)
我认为的具有生成性。它以一个序列作为输入,并在每一步生成一个新的事物-因此,你最终会得到一个新事物序列。生成时不可能更新产品城市
reduce
对于您想要做的事情更有用,因为您得到了一个“累加器”,可以在每个步骤中稍微修改它。实际上,您每次都在通过修改传入的“累加器”来创建一个新的“累加器”,所以实际上您根本没有修改任何东西:Clojure是一种函数式语言,它的全部内容都是创建新事物 你似乎对clojure的工作原理有一些误解。来自java,可能很难知道如何做事情,只是因为它太不一样了。这个小问题很好地介绍了如何建立价值,我将尝试解释解决方案的每个部分
不变性
java中的一种常见模式是定义一个保存最终结果的变量,然后在添加到该变量时循环执行某些内容
这就是你想用你的产品城市
本地做的。当您在clojure中使用定义一个局部变量时,它永远不会改变,因此要建立一个值,您需要另一个模式
向地图添加内容
首先,我们来看看如何“添加一些东西到地图”。在clojure中,您实际要做的是用添加的东西制作一个新地图。旧地图不变。我们有时仍将其表述为添加到地图中,但这只是“使用添加的内容制作新地图”的简写
assoc
获取一个映射、一个键和一个值,并返回一个新映射,其中的值在键处添加。如果已经存在一个值,它将被覆盖。我们希望每个键都有多个属性,所以在这种情况下这不是正确的
update
与之类似,但它需要一个映射、一个键、一个函数以及该函数的可选参数。它将使用键中已经存在的值作为第一个参数和(如果存在)提供的参数调用函数。返回的映射将函数的返回值作为键处的新值。一些例子可能会更清楚地说明这一点
;; The function - is called with the old value of :foo and the argument supplied
;; (- 10 3)
(update {:foo 10} :foo - 3) ;=> {:foo 7}
如果键上没有任何内容,则将使用nil
作为第一个参数调用该函数。这就是nil
的意思,没有
(update {} :foo + 5) ;=> Null pointer exception. Same as (+ nil 5)
空指针是不好的。有一个技巧可以避免它们fnil
是一个接受函数和参数的高阶函数。它返回一个新函数,用nil
参数替换提供的参数
;; The nil here is substituted with 0, so no NPE
((fnil + 0) nil 5) ;=> 5
;; If the arg is not nil, the zero is not used.
((fnil + 0) 5 5) ;=> 10
;; So now we can update the value at :foo regardless of whether it's already there.
(update {} :foo (fnil + 0) 5) ;=> {:foo 5}
conj
向集合中添加内容。如果该集合是一个向量,则会将其添加到末尾
(conj [] :foo) ;=> :foo
(conj [:foo] :bar) ;=> [:foo :bar]
要向地图中添加内容,我们可以将以下内容组合在一起:
(update {} "product" (fnil conj []) "city") ;=> {"product ["city"]"}
(update {"product" ["city"]} "product" (fnil conj []) "another city")
;;=> {"product" ["city" "another city"]}
建立价值观
我们需要做一些循环。然而,clojure中的for
是一个列表理解,而不是for循环。它将返回一个th序列
(reduce (fn [product-cities {:keys [product city]}]
(update-in product-cities [product] (fnil conj []) city))
{}
table)