将列表列表转换为Clojure中列表列表的映射

Bil*_*ll 2 maps list clojure

我有一个列表的列表,并希望进入一个地图,关键是在列表中的共同价值观之一(在这个例子中动物名)这一点.我知道如何使用{}和从列表创建一个地图,但这不是我想要的.我希望地图中的键(动物名称)引用这些值的列表列表.

我已经创建了一个列表列表

(def animals (list '("tiger" "fur" "yellow & black stripes") '("tiger" "weight" "150") '("tiger" "home" "India") '("elephant" "skin" "gray") '("elephant" "weight" "1500") '("elephant" "home" "Africa") '("frog" "skin" "green") '("frog" "diet" "insects")))
Run Code Online (Sandbox Code Playgroud)

动物

(("tiger" "fur" "yellow & black stripes") ("tiger" "weight" "150") ("tiger" "home" "India") ("elephant" "skin" "gray") ("elephant" "weight" "1500") ("elephant" "home" "Africa") ("frog" "skin" "green") ("frog" "diet" "insects"))
Run Code Online (Sandbox Code Playgroud)

这不完全符合我的要求(但差不多)

(def animal-map (into {} (for [[name attribute value] animals] [name (list attribute value)])))
Run Code Online (Sandbox Code Playgroud)

当我想要每个键的多个列表时,这会导致每个键只有一个列表

动物图(列表地图)

{"tiger" ("home" "India"), "elephant" ("home" "Africa"), "frog" ("diet" "insects")}
Run Code Online (Sandbox Code Playgroud)

这是我想要最终结果.

动物图(列表清单)

{"tiger" ("fur" "yellow & black stripes") ("weight" "150") ("home" "India"),   
"elephant" ("skin" "gray") ("weight" "1500") ("home" "Africa"),   
"frog" ("skin" "green") ("diet" "insects")}  
Run Code Online (Sandbox Code Playgroud)

Bri*_*per 8

关于您期望的结果,您发布的最终地图并没有按照您的想法进行.在这张地图中:

{"tiger" ("fur" "yellow & black stripes") ("weight" "150") ("home" "India")}
Run Code Online (Sandbox Code Playgroud)

这不是具有一个键和三个值的映射,这是具有两个键("tiger"("weight" "150"))和两个值的映射.

以下内容并未直接回答您的问题,而是关于惯用Clojure的一句话.如果您为手头的工作选择合适的数据结构,您将在Clojure中度过更轻松的时光.

对于您的初始数据,您应该使用向量而不是列表,除非您有充分的理由使用列表.向量对于许多操作(例如随机访问)执行得更好; 你不需要像你做一个列表那样引用一个向量; 和向量表示您正在处理数据而不是代码.

如果您的数据必须从前面而不是后面增长,或者如果您将源代码生成为数据(例如,在宏中),则列表是合适的.

[["tiger" "fur" "yellow & black stripes"]
 ["tiger" "weight" "150"]
 ["tiger" "home" "India"]
 ...]
Run Code Online (Sandbox Code Playgroud)

对于最终数据,请考虑使用字符串映射来映射而不是将字符串映射到列表.使用地图创建地图很容易,assoc-in因为它会为您创建中间地图.然后,您可以使用访问数据的子键get-in.

要在字符串映射中访问动物的属性到列表,您必须对属性列表进行线性搜索.这对代码来说很尴尬并且表现不佳.

user> (def animal-map (reduce (fn [m [animal k v]]
                                (assoc-in m [animal k] v))
                              {} animals))
#'user/animal-map
user> animal-map
{"frog" {"diet" "insects", "skin" "green"}, 
 "elephant" {"home" "Africa", "weight" "1500", "skin" "gray"}, 
 "tiger" {"home" "India", "weight" "150", "fur" "yellow & black stripes"}}

user> (get-in animal-map ["frog" "diet"])
"insects"
Run Code Online (Sandbox Code Playgroud)

最后,我不确定这些数据的来源,但考虑使用关键字而不是字符串来实现这些键.它可能适合或不适合动物的名字,但它几乎肯定适合动物的属性(体重,家庭,饮食).

如果您的密钥是关键字,您甚至不需要get-in,您可以直接使用关键字作为函数,或使用->.你不能用字符串来做这件事.

user> (def animal-keyword-map (reduce (fn [m [animal k v]]
                                        (assoc-in m [(keyword animal) (keyword k)] v))
                                      {} animals))
#'user/animal-keyword-map
user> animal-keyword-map
{:frog {:diet "insects", :skin "green"}, 
 :elephant {:home "Africa", :weight "1500", :skin "gray"}, 
 :tiger {:home "India", :weight "150", :fur "yellow & black stripes"}}
user> (:weight (:tiger animal-keyword-map))
"150"
user> (-> animal-keyword-map :tiger :weight)
"150"
Run Code Online (Sandbox Code Playgroud)