Clojure - 密钥本身很复杂的随机访问

时间:2015-09-12 01:47:22

标签: clojure

向量适用于随机访问,但关键是它在序列中的位置,只是一个数字。当您希望密钥本身更有趣,并且您想要快速随机访问时怎么办?为此,明显的候选人似乎是一张地图。在大多数Map示例中,使用的键是关键字(前面有两个点)。我可以使用Vector作为Map的键吗?或者不是“可以”,但这是一个惯用的事情吗?那里有这种事情的例子吗?在某种程度上,我在关系数据库术语中思考,除了结构保存在内存中。

3 个答案:

答案 0 :(得分:2)

我已经这样做了 - 用其他东西作为钥匙。成语?为什么不?你几乎可以用任何东西作为钥匙。 (也许其他人会有不同的意见。)

Lookup将遵循Clojure的等式语义。有趣的地方是你想要使用defrecord或deftype作为键。这些功能在某些方面类似,但deftype相等通常是通过标识,即=等同于identical?的deftypes(但请参见下面的amalloy评论)。我相信函数也有身份语义。

(defrecord BarRec [x y])

(deftype BarTyp [x y])

(def foo {125 1, 
          "this" 2, 
          {:a 10 :b 20} 3, 
          [1 2 3] 4, 
          (->BarRec 10 20) 5, 
          (BarTyp. 10 20) 6})

请注意,我在下面创建了每个键的新实例:

(foo 125) ;=> 1
(foo "this") ;=> 2
(foo {:b 20 :a 10}) ;=> 3
(foo [1 2 3]) ;=> 4
(foo (->BarRec 10 20)) ;=> 5
(foo (->BarTyp 10 20)) ;=> nil

新的deftype实例找不到使用旧deftype实例作为键的映射条目,即使它们具有相同的内容。这里有一个线索,原因是:

(= (->BarRec 10 20) (->BarRec 10 20)) ;=> true
(= (->BarTyp 10 20) (->BarTyp 10 20)) ;=> false
(def bar-typ (->BarTyp 10 20))
(= bar-typ bar-typ) ;=> true

这意味着在某些情况下使用deftypes作为键比使用defrecords更有效:比较两个defrecords需要比较它们的内容,而比较deftypes只需要决定某些东西是否是同一个对象 - 可能是通过指针相等。 / p>

然而,defrecords包含许多deftypes没有的便利。而且,defrecords是 Clojurely 。严格认同的平等不是 Clojurely 。如果您想要跟踪其内容随时间变化的数据结构,那么通过身份进行的平等是有用的,但是这种野兽不应该在Clojure森林中疯狂地运行。你几乎可以说deftypes从一开始就被创建了一个弃用的状态(但它们永远不会离开)。

(注意:有关defrecords和deftypes的哈希效率之间差异的观点转移到Java互操作。两个数据结构都可以被视为Java类,当Java哈希映射比较两个defrecords或两个deftypes时,它会调用{ {1}}遵循适当的Clojure语义的方法。在Java中使用deftypes作为哈希键可以快得多。)

答案 1 :(得分:0)

我认为没有很多Clojure“随机访问”的例子的原因是这样做并不是一种功能性的编程方式。如果“一切都是一条小溪”(在技术意义上不是那么多,而是在“过去的”意义上),那么所需要的就应该已经存在了。

要修复,程序中现有的流生成函数可能会使其生成的每个项目“更大”。或者可以从reduce而不是one返回两个累加器:

https://gist.github.com/stathissideris/9500581

在我的情况下,我已经创建了一个位置流,并且需要随机访问其他东西(Blob)。所以我创建了一个现有的reduce函数返回元素,它们具有位置和Blob,已经彼此相邻 - 所以不需要随机访问Blob来提示这个问题。

答案 2 :(得分:0)

您可以在Clojure地图中使用所有类型的对象作为键。它们旨在支持这种用途。您经常看到带有关键字的地图的原因是因为它们也等同于OO语言中的数据对象。