【发布时间】:2023-03-26 18:08:01
【问题描述】:
给定集合中的成员,返回集合中下一项的惯用方式是什么?
例如,给定(def coll [:a :b :c :d :e :f]),f 应该是什么让(f coll :d) 返回:e?
【问题讨论】:
标签: clojure
给定集合中的成员,返回集合中下一项的惯用方式是什么?
例如,给定(def coll [:a :b :c :d :e :f]),f 应该是什么让(f coll :d) 返回:e?
【问题讨论】:
标签: clojure
通常,这在 Clojure 中并不常见。唯一可能的实现需要对输入集合进行线性扫描,这意味着您为此任务使用了错误的数据结构。
相反,我们通常会尝试对数据进行结构化,以便于我们需要对其执行的任务。如何最好地做到这一点将取决于为什么您要查找“foo 之后的元素”。例如,如果您一次输入一个项目,并且想知道下一个项目以及当前项目,您可以编写 (partition 2 1 input) 以获取相邻值对的序列。
也就是说,您要求一个惯用的实现,但没有:惯用语是以不同的方式解决问题。当然,如果您认为自己处于特殊情况下,您使用正确的数据结构并且只需要执行一次或两次这种奇怪的事情,那么您自己编写循环当然很简单。
【讨论】:
正如@amalloy 在他的回答中所说,这不是您想要使用原始数据结构的东西,因为它每次都需要线性查找。换句话说,您的 (f coll :d) 模式由于其性能而不会特别有用。
但是,您可以做的是定义一个函数,给定一个集合,构建一个数据结构,使这种查找变得高效,并将其用作您的函数。它可能看起来像这样:
(defn after [xs]
(into {} (map vec (partition 2 1 xs))))
例子:
(-> [:a :b :c :d :e :f] after :d)
;;=> :e
(let [xs [:a :b :c :d :e :f]
f (after xs)]
(map f xs))
;;=> (:b :c :d :e :f nil)
【讨论】:
如果我们将问题概括为在通过测试的第一件事之后找到事物,我们会得到类似
(defn following [pred coll]
(->> coll
(drop-while (complement pred))
(second)))
例如,
(following #{6} (range))
=> 7
或者,你的例子,
(following #{:d} coll)
=> :e
这与take-while 或drop-while 差不多。
【讨论】: