0

contains?我是 clojure 的新手,对将表单用于不同的数据结构有点困惑。

应用于contains向量、集合或映射的结果正是我所期望的,它测试集合中是否存在键(或索引)。但是当涉及到一个列表时,例如


(def li '(1 2 3)) ; define a list
(contains? li 1) ; returns false !!??

我知道要理解如何contains?使用列表并不是那么简单,因为它的文档说实现在恒定或日志时间内运行。因此,如果 1 在列表或其索引范围内,那么在少于日志时间的时间内进行测试是没有意义的。但在那种情况下,为什么它不会像使用assoc列表一样引发异常。在这种assoc情况下,哲学是相同的 -assoc不应该应用于列表,因为它不支持对其元素进行足够快的随机访问。

(vals a-map)我觉得这很不方便,因为clojure中的很多表单都返回一个通用集合作为结果,例如说同一件事的不同方式。


(def a-map {:one 1 :two 2})
(contains? (vals a-map) 1) ; returns false!!
(contains? (set (vals a-map)) 1); returns true!!

所以经过长时间的解释,我的问题是——这个设计背后的理性是什么?当我们想在clojure中测试一个元素是否在一个map的值集中时,我们应该如何原生地说,即更重要的是,我应该如何说服自己,这样我就不会在实践中犯下愚蠢的错误?谢谢!

4

2 回答 2

4

源代码显示,对于 clojure 直到 1.4 版(包括 1.4 版)contains?,列表总是返回 false(它一直到第 713 行)。

最新的 1.5 beta中,它会抛出异常。

于 2013-01-12T10:30:12.120 回答
1

contains?仅用于键控集合(例如,任意键/值对的映射,具有整数索引的索引集合的向量)。请参阅文档字符串:

clojure.core/contains?
([coll key])
  Returns true if key is present in the given collection, otherwise
  returns false.  Note that for numerically indexed collections like
  vectors and Java arrays, this tests if the numeric key is within the
  range of indexes. 'contains?' operates constant or logarithmic time;
  it will not perform a linear search for a value.  See also 'some'.

就个人而言,我认为它的名字很糟糕,应该被称为has-key?或类似的东西。但那是过去的历史——除非有人(即 Rich 决定对 API 进行重大更改),否则我们会坚持下去。

可以说,如果contains?曾经给您带来问题,那么从算法的角度来看,您可能做错了什么:您可能不应该对集合进行顺序搜索来查找值,而应该使用映射或集合。

但要回答这个问题:我同意你的观点,当应用于不支持键控查找(如列表)的东西时,包含抛出异常会更有意义。它与文档字符串不矛盾,因为这种行为是未定义的,所以也许值得补丁?

编辑:我从@ivant 的回答中看到,最新的 1.5 测试版确实会在列表中引发异常。问题已经解决了!

于 2013-01-12T10:35:23.627 回答