什么';在clojure中存储对象及其功能的最佳方式是什么?

什么';在clojure中存储对象及其功能的最佳方式是什么?,clojure,Clojure,一个对象至少有它的位置和尺寸,但可能有其他字段,例如 (def obj1 '(cup1 x 0 y 0 z 0 width 10 height 10)) (def obj2 '(cup2 x 0 y 0 z 0 width 10 height 10)) (def objs '(obj1 obj2)) 如果我想访问和修改值,比较它们的名称或维度,并允许我将来可能添加新字段,那么存储这些类型对象的最有效方法是什么 是否有类似python中的有序字典的东西?Clojure映射非常常用于此类事情,通常

一个对象至少有它的位置和尺寸,但可能有其他字段,例如

(def obj1 '(cup1 x 0 y 0 z 0 width 10 height 10))
(def obj2 '(cup2 x 0 y 0 z 0 width 10 height 10))
(def objs '(obj1 obj2))
如果我想访问和修改值,比较它们的名称或维度,并允许我将来可能添加新字段,那么存储这些类型对象的最有效方法是什么


是否有类似python中的有序字典的东西?

Clojure映射非常常用于此类事情,通常使用Clojure关键字作为键,但键可以是字符串、符号、数字、向量等,任何不可变的Clojure值:

(def obj1 {:name "cup1" :x 0 :y 0 :z 0 :width 10 :height 10})
(def obj2 {:name "cup2" :x 0 :y 0 :z 0 :width 10 :height 10})
(def objs [obj1 obj2])
Clojure映射是无序的,可以通过键快速查找以获得相应的值,并通过函数
assoc
和其他一些内置函数快速“更新”,即“返回一个新映射,其中一个或多个键具有与其相关联的新值”


有一个第三方库,它提供的映射可以记住键/值对相对于彼此的插入顺序,但Clojure开发人员很少使用它们:

Clojure映射非常常用于这类事情,通常使用Clojure关键字作为键,但键可以是字符串、符号、数字、向量等。,任何不可变的Clojure值:

(def obj1 {:name "cup1" :x 0 :y 0 :z 0 :width 10 :height 10})
(def obj2 {:name "cup2" :x 0 :y 0 :z 0 :width 10 :height 10})
(def objs [obj1 obj2])
Clojure映射是无序的,可以通过键快速查找以获得相应的值,并通过函数
assoc
和其他一些内置函数快速“更新”,即“返回一个新映射,其中一个或多个键具有与其相关联的新值”


有一个第三方库,它提供的映射可以记住键/值对相对于彼此的插入顺序,但Clojure开发人员很少使用它们:

如果所有字段都同等重要,那么a就很好,但是找到一个单一的对象会很慢,因为你需要遍历整个列表来寻找它。如果每个对象的“名称”是唯一的/主键,则可以使用贴图贴图,而不是通过名称轻松(快速)查找单个对象

(def objs
{“cup1”{:x0:y0:z0:width 10:height 10}
“cup2”{:x0:y0:z0:宽10:高10})
;; 按名称检索(如果找不到名称将出错)
(获取objs“cup1”)
;; 添加(将替换具有相同名称的任何现有obj)
(关联对象“cup3”{:x0:y0:z0:宽10:高10})
;; 删除(即使找不到名称也不会出错)
(dissoc objs“cup3”)
;; 按名称更新(如果找不到名称将出错)
(objs中的助理[“cup1”:x]5)
;; 获取没有名称的所有对象(即地图列表)
(VAL objs)
;; 获取所有具有名称的对象
(地图(fn[[n obj]]
(助理对象:名称n))
objs)
请注意,除非另有规定,否则Clojure中的所有内容都是不可变的,因此上述所有操作都将生成一个单独的数据结构,保留原始数据结构不变。实际上没有任何东西被“更新”或“覆盖”或“删除”——Clojure只是简单地向您返回数据的视图,如果完成这些操作,数据会是什么样子

Clojure的主要网站上有一个专门讨论这一问题的部分

要将问题中的数据结构转换为此地图,您可以:

;;毫无疑问
(def obj1'(cup1 x 0 y 0 z 0宽10高10))
(def obj2'(cup2 x 0 y 0 z 0宽10高10))
(def objs'(obj1 obj2))
;; 由于“(obj1 obj2)仅包含符号,而不包含对obj1和obj2的引用,
;; 有必要将其按如下方式存储:
(def objs[obj1 obj2])
(定义地图键)
“将函数f应用于地图m的每个键。
例如:(地图键公司{1100 2200})->{2100 3200}”
[f m]
(减少千伏(fn f-f-f-k[acc k v]
(助理行政协调(f k)v)
(空m)m)
(定义符号列表->地图
“将OP的符号列表转换为具有字符串化名称的关键字化映射。
例如:(symlist->map'(a x 1))->{:name\'a\':x 1}”
[符号列表]
(更新(地图关键字)
(应用哈希映射(conj符号列表的名称)))
:姓名(str))
(def obj查找
(->objs
(映射(comp(juxt:name-identity)符号列表->映射)
(变成{})
;; 现在你可以
(获取obj查找“cup1”)
上面将名称转换为字符串,但您可以通过从
symlist->map
中删除
(更新…:name str)
(甚至可以通过删除
(map keys关键字…
)将属性名称保留为符号)将名称保留为符号。事实上,只要正确实现
hashCode
等于
,几乎任何东西都可以成为Clojure哈希映射(甚至是整个其他映射,尽管这不是常见的用例)中的键

如果出于任何原因,您需要返回到原始结构,类似的操作将起作用:

(映射(fn[[obj name obj properties]]
(序号(减少(fn表示分录[acc[k v]]
(联合附件(符号k)v)
[(符号obj名称)]obj属性])
obj查找)
显然,如果您决定将所有键作为符号保留在所有位置,则更简单,因为不需要将其转换回符号:

(映射(fn[[obj name obj properties]]
(conj(展平(序列obj属性))obj名称)
obj查找)

如果所有字段都同等重要,则a很好,但查找单个对象会很慢,因为您必须遍历整个列表才能找到它。如果每个对象的“名称”是唯一的/主键,则可以使用贴图贴图,而不是通过名称轻松(快速)查找单个对象

(def objs
{“cup1”{:x0:y0:z0:width 10:height 10}
“cup2”{:x0:y0:z0:宽10:高10})
;; 按名称检索(如果找不到名称将出错)
(获取objs“cup1”)
;; 添加(将替换具有相同名称的任何现有obj)
(关联对象“cup3”{:x0:y0:z0:宽10:高10})
;; 删除(即使找不到名称也不会出错)
(dissoc objs“cup3”)
;; 按名称更新(将更新)