【问题标题】:Recursively reverse a sequence in Clojure在 Clojure 中递归地反转一个序列
【发布时间】:2012-01-13 18:27:14
【问题描述】:

我想在不使用 reverse 函数的情况下在 Clojure 中反转一个序列,并递归地这样做。

这是我想出的:

(defn reverse-recursively [coll]
  (loop [r (rest coll)
         acc (conj () (first coll))]
    (if (= (count r) 0)
      acc
      (recur (rest r) (conj acc (first r))))))

示例输出:

user> (reverse-recursively '(1 2 3 4 5 6))
(6 5 4 3 2 1)
user> (reverse-recursively [1 2 3 4 5 6])
(6 5 4 3 2 1)
user> (reverse-recursively {:a 1 :b 2 :c 3})
([:c 3] [:b 2] [:a 1])

问题:

  1. 有没有更简洁的方法来做到这一点,即没有循环/递归?
  2. 有没有办法在循环中不使用“累加器”参数来做到这一点?

参考资料:

Whats the best way to recursively reverse a string in Java?

http://groups.google.com/group/clojure/browse_thread/thread/4e7a4bfb0d71a508?pli=1

【问题讨论】:

  • 您是否可能尝试过this 4clojure problem? :)
  • 不,我不是。 “递归地反转一个字符串”是一个很常见的面试问题。

标签: recursion clojure


【解决方案1】:

为了详尽无遗,还有一种使用into 的方法。由于 into 内部使用 conj 它可以如下使用:

(defn reverse-list 
  "Reverse the element of alist."
  [lst]
  (into '() lst))

【讨论】:

    【解决方案2】:
    (defn recursive-reverse [coll]
      (if (empty? coll)
        ()
        (concat (vector (peek coll)) (recursive-reverse (pop coll )))
      )
    )
    and test:
    user=> (recursive-reverse [1])       
    (1)
    user=> (recursive-reverse [1 2 3 4 5])
    (5 4 3 2 1)
    

    【讨论】:

      【解决方案3】:
      (defn reverse-seq [sss]
        (if (not (empty? sss))
          (conj (reverse-seq (rest sss)) (first sss))
        )
      )
      

      【讨论】:

        【解决方案4】:

        在当前版本的 Clojure 中有一个名为 rseq 的内置函数。对于任何路过的人。

        【讨论】:

        • rseq 要求输入序列为Reversible,这使得它通常不适合(不适用于cons 列表、PersistentListLazySeq、带字符串) .它旨在优化可以在恒定时间内反转的序列。
        【解决方案5】:

        对问题 1 是的,这就是我对递归公案的回答(我无法告诉你这是否是好的 clojure 练习)。

        (defn recursive-reverse [coll]
            (if (empty? coll)
                []
                (conj (recursive-reverse (rest coll)) (first coll) )))
        

        【讨论】:

        • 好吧,试试这个:(recursive-reverse (apply str (seq (take 100000 (repeat "foo")))))
        • 很公平,我刚刚到了那个公案的最后一部分,如果没有循环/递归构造,阶乘函数就会溢出。所以我想现在我可以说这不是一个好习惯:) - 干杯!
        • 这真的很优雅!
        【解决方案6】:
        • 您无需计算。当剩余序列为空时停止。
        • 您不应该预先填充 acc,因为原始输入可能是空的(而且是更多代码)。
        • 解构很酷。
        (defn 反向递归 [coll] (loop [[r & more :as all] (seq coll) acc'()] (我摔倒 (重复出现更多(cons r acc)) ac)))

        对于loop/recuracc,您需要某种方式来传递工作反向列表。要么是loop,要么向函数添加另一个参数(这实际上是loop 正在做的事情)。

        或者使用高阶函数:

        用户=> (减少 conj '() [1 2 3 4]) (4 3 2 1)

        【讨论】:

        • 关于“使用高阶函数”查看(source reverse)
        • repl 在此函数应用 map ({:a 1 :b 2 :c 3}) 时中止。
        • 好吧,从技术上讲,我的问题是“反转序列”而不是“反转任何东西,包括地图”,所以我认为这个问题并不排除它。这是错误,顺便说一句:Clojure> (reverse-recursively {:a 1 :b 2})java.lang.UnsupportedOperationException: nth not supported on this type: PersistentArrayMap
        • 另外,看起来循环/递归当然需要尾递归,但它在 Clojure 中被认为是“代码气味”:twoguysarguing.wordpress.com/2010/07/26/…
        • @noahz 实际上这篇文章说“循环/递归是不是代码异味,但要怀疑它”。我猜他们的意思是更喜欢 map、reduce 等,但它们并不总是提供解决方案。
        【解决方案7】:
        (defn my-rev [col]
          (loop [ col col
                  result []]
                (if (empty? col)
                    result
                    (recur (rest col) (cons (first col) result)))))
        

        第一季度。

        JVM不能优化递归,递归函数会直接和栈溢出。因此,在使用循环/递归的 Clojure 中。因此,如果不使用递归函数,则无法定义深度递归。 (也用于内部作为函数 trampoline 递归。)

        第二季度。

        recur 的递归函数,必须是尾递归的。如果普通递归函数变为尾递归函数,那么就需要携带一个变量的值作为累加器。

        【讨论】:

        • map 序列的顺序不会改变执行。但订单将被执行。
        • 我不明白你的评论。 “订单即将执行?”
        • @noahz, (rev {:a 1 :b 2 :c 3})->([:c 3] [:b 2] [:a 1]) 不一定如此。 Clojure1.3.0 我的结果是 ([:b 2] [:c 3] [:a 1])
        • 啊,因为 Clojure 中的 PersistentArrayMapjava.util.HashMap 一样是无序的?这是不直观的。
        • 我知道。地图一般是不定顺序知道的。为了它们被插入,如示例中所示必须必须。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-12-14
        • 2014-04-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多