【问题标题】:What is the API for PersistentQueue?PersistentQueue 的 API 是什么?
【发布时间】:2016-06-05 17:34:55
【问题描述】:

PersistentQueue 的 API 是什么?

天真,它似乎丢失了放入其中的所有数据:

user=> (def q (into (clojure.lang.PersistentQueue/EMPTY)
                    (repeat 5 nil)))
#'user/q
user=> (def q2 (pop (conj q :a)))
#'user/q2
user=> (get q2 4)
nil
user=> (get q2 0)
nil

我一定没有正确访问 PersistentQueue。显然它不适用于get。访问 PersistentQueue 的正确方法是什么? 可以用它做什么?

PersistentQueue 是否记录在任何地方,甚至是非正式的? (“它只在我的答案中完整记录”很好。真的,我希望有人会在答案中写下缺少的文档,或者告诉在哪里可以找到它,如果它没有丢失。)

【问题讨论】:

    标签: data-structures clojure queue


    【解决方案1】:

    conj 从不改变它的参数,它返回一个不可变的新数据结构,并且可以在内部与原始数据结构共享数据。但我想你已经知道这部分了。

    get 仅适用于关联数据,如果用于非关联数据,则返回 nil 而不是错误。队列不是关联的。在您的示例中,通过将 nil 放入队列中部分掩盖了此问题,这使得 get 返回的 nil 不明确。

    user=> (def q (into clojure.lang.PersistentQueue/EMPTY (repeat 5 :a)))
    #'user/q
    user=> (into [] q)
    [:a :a :a :a :a]
    user=> (def q2 (pop (conj q :b)))
    #'user/q2
    user=> (into [] q2)
    [:a :a :a :a :b]
    user=> (get q2 4)
    nil
    user=> (get q2 0)
    nil
    user=> (nth q2 4)
    :b
    user=> (nth q2 0)
    :a
    

    通常,与队列一起使用的正确操作是 conjintopeekpop

    user=> (def q3 (-> q2 (pop)
                          (conj :c :d)
                          (pop)
                          (conj :e)
                          (pop)
                          (pop)
                          (conj :f)))
    #'user/q3
    user=> (into [] q3)
    [:b :c :d :e :f]
    user=> (peek q3)
    :b
    

    【讨论】:

    • 感谢您对into 的建议。我只是把它放到我的真实代码中。我也会更新这个问题(再次,只是为了保持重点)。
    • nth 是 PersistentQueue 的典型正确操作之一吗?我对 PersistentQueue 的直接用途是保留最近状态的一些历史记录,在 5 个时间步后将它们丢弃。我需要能够查找“3 个时间步前发生了什么?”这超出了 PersistentQueue 的定义吗?
    • 这是队列的一个很好的用途,真的。 nth 在队列中不是 super 快,但对于小 N 来说没问题。您还可以查看我的ring-buffer,了解一个类似队列的结构,自动驱逐最旧的条目。
    • @amalloy 谢谢!我去看看。这可能正是我所需要的,因为 PersistentQueue 似乎不是(相当)适合这项工作的工具。
    【解决方案2】:

    顺序收集的协议是

    • (conj coll x) - 返回集合coll 并将x 添加到一端或另一端;
    • (peek coll) - 从coll 返回下一个要丢弃的项目,如果有的话;
    • (pop coll) - 返回coll 减去丢弃的一端。

    peekpop 总是在同一端工作:

    • 列表(或一般序列)的前面;
    • 向量或队列的后面。

    conj 与向量或列表的peek/pop相同 端工作,但在向量或列表的相反 端(前面)队列。这就是使它作为队列工作的原因。

    如前所述,getdisj 与顺序收集无关。

    您可能会感到困惑,因为PersistentQueue 不知道如何正确地将自己转换为字符串。 seq 会告诉你你有什么。例如,

    (def q (into (clojure.lang.PersistentQueue/EMPTY)
                        (repeat 5 nil)))
    
    q ;=>#<PersistentQueue clojure.lang.PersistentQueue@1b4d89f>
    
    (seq q) ;(nil nil nil nil nil)
    

    【讨论】:

    • 哦..,所以nth 之所以有效,只是因为它反复弹出然后偷看? PersistentQueue 是否支持除了三个顺序收集之外的任何其他操作?
    • 任何顺序集合都是一个序列,或者至少是可序列的。所以它支持所有的序列操作。 nth 是一个混合体:它像 get 在向量等上工作;但作为重复的nextrest 将在序列(包括顺序集合)上,作为重复的pop
    猜你喜欢
    • 2011-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-27
    • 2016-08-23
    • 2010-10-09
    • 2011-01-11
    相关资源
    最近更新 更多