Clojure:O(1)函数检查序列是否恰好有1个元素

时间:2016-07-15 06:16:23

标签: performance clojure functional-programming predicate

有没有一种快速的方法来检查一个序列在Clojure中是否只有1个元素?请注意,序列可能包含nils。

如果我正确读取source,则在序列上调用count需要花费O(n)时间。

替代解决方案:

(and
  (not (empty? a-seq))
  (empty? (rest a-seq)))

Docs说在集合empty?上调用coll与调用(not (seq coll))相同,但是他们没有指定效率或调用{{{}时发生的情况1}}关于一个序列。我试图在github存储库中搜索empty?的实现方式,但它忽略了搜索中的问号,并且“空”上有大量点击。我认为empty?empty?是O(1),但是再次,rest不是......

4 个答案:

答案 0 :(得分:3)

因为

reflect.TypeOf(myVar)

(函数终止的事实),我假设user=> (empty? (cycle [1])) false 在恒定时间内进行求值,即empty?在恒定时间内初始化序列。

(seq coll)

你的代码做得很好。也许我会说:

user=> (source empty?)
(defn empty?
  "Returns true if coll has no items - same as (not (seq coll)).
  Please use the idiom (seq x) rather than (not (empty? x))"
  {:added "1.0"
   :static true}
  [coll] (not (seq coll)))
nil

答案 1 :(得分:3)

1.9中添加了以下功能(截至目前仍为alpha版):

(defn bounded-count
  "If coll is counted? returns its count, else will count at most the first n
  elements of coll using its seq"
  {:added "1.9"}
  [n coll]
  (if (counted? coll)
    (count coll)
    (loop [i 0 s (seq coll)]
      (if (and s (< i n))
        (recur (inc i) (next s))
        i))))

所以我想(bounded-count 2 coll)应该为你提供所需的恒定时间。

答案 2 :(得分:3)

当序列变得懒惰时,你无法真正谈论“恒定时间”,因为在构造输入序列时可能会延迟任何工作量。例如,请考虑以下序列:

(filter even? (filter odd? (range)))

对此序列调用seq将永远不会返回任何类型的结果,除非您等待的时间超过Long/MAX_VALUE

但是,通常,功能完全按照他们需要做的最少工作量来完成。所以seq做了足够的工作来确定集合的第一个元素是什么,如果有的话,next只做足够的工作来确定第一个和第二个元素是什么,如果有的话。

答案 3 :(得分:1)

几点说明:

  

文档说在集合上调用empty?与调用相同   (not (seq coll)),但他们没有指定效率或发生的事情   当你在一个序列上调用empty?时。

empty?适用于序列,无论是否基于集合。 已定义作为seq的补充:

(defn empty? [coll]
  (not (seq coll)))

我将您的功能重写为

(defn one-element? [coll]
  (and (seq coll)
       (empty? (rest coll))))

(defn one-element [coll]
  (and (seq coll)
       (not (next coll))))

这些速度与seqrest / next的速度顺序相同。