【问题标题】:What is the idiomatic way of returning the next member in collection?返回集合中的下一个成员的惯用方式是什么?
【发布时间】:2023-03-26 18:08:01
【问题描述】:

给定集合中的成员,返回集合中下一项的惯用方式是什么?

例如,给定(def coll [:a :b :c :d :e :f])f 应该是什么让(f coll :d) 返回:e

【问题讨论】:

    标签: clojure


    【解决方案1】:

    通常,这在 Clojure 中并不常见。唯一可能的实现需要对输入集合进行线性扫描,这意味着您为此任务使用了错误的数据结构。

    相反,我们通常会尝试对数据进行结构化,以便于我们需要对其执行的任务。如何最好地做到这一点将取决于为什么您要查找“foo 之后的元素”。例如,如果您一次输入一个项目,并且想知道下一个项目以及当前项目,您可以编写 (partition 2 1 input) 以获取相邻值对的序列。

    也就是说,您要求一个惯用的实现,但没有:惯用语是以不同的方式解决问题。当然,如果您认为自己处于特殊情况下,您使用正确的数据结构并且只需要执行一次或两次这种奇怪的事情,那么您自己编写循环当然很简单。

    【讨论】:

      【解决方案2】:

      正如@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)
      

      【讨论】:

        【解决方案3】:

        如果我们将问题概括为在通过测试的第一件事之后找到事物,我们会得到类似

        (defn following [pred coll]
          (->> coll
               (drop-while (complement pred))
               (second)))
        

        例如,

        (following #{6} (range))
        => 7
        

        或者,你的例子,

        (following #{:d} coll)
        => :e
        

        这与take-whiledrop-while 差不多。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-10-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-10-21
          • 2011-03-07
          相关资源
          最近更新 更多