我正在尝试在clojure中实现深度逆转。如果lst是(1(2(3 4 5))(2 3)),它应该返回((3 2)((5 4 3)2)1)。
这是我到目前为止:
defn dRev [lst]
( if (= lst ())
nil
( if (list? (first lst))
( dRev (first lst) )
( concat
( dRev (rest lst)) (list (first lst))
)
)
)
)
但是,我的实现仅在嵌套列表是最后一个元素时才有效,但结果列表也是平展的。
例如:(dRev'(1 2(3 4))将返回(4 3 2 1) 否则,例如:(dRev'(1(2 3)4))将仅返回(3 2 1)。
我现在打了这个砖墙一段时间了,我无法找到我的代码问题。
有人可以帮帮我吗?
答案 0 :(得分:7)
另一个答案为您提供了Clojure中深度反转的最佳实现,因为它使用了clojure.walk/postwalk
函数,该函数概括了将函数深度应用于集合的每个元素的问题。在这里,我将向您介绍您发布的实施问题。
首先,不寻常的格式化使得很难发现正在发生的事情。以下是固定格式的相同内容:
(defn dRev [lst]
(if (= lst ())
nil
(if (list? (first lst))
(dRev (first lst))
(concat (dRev (rest lst))
(list (first lst))))))
接下来,还有其他一些尚未解决此问题的小修补程序:
coll
而不是lst
,empty?
检查空集合,()
因为我们知道要返回列表而不是其他类型的seq,coll?
代替list?
因为我们也可以反转任何集合而不仅仅是列表:(如果你真的想要只反转列表并保留所有其他集合,请反转最后一次更改。)
(defn d-rev [coll]
(if (empty? coll)
()
(if (coll? (first coll))
(d-rev (first coll))
(concat (d-rev (rest coll))
(list (first coll))))))
现在,格式化修复显示了实现的主要问题:在递归调用((d-rev (first coll))
resp。(dRev (first lst))
)中,只返回该递归的结果,但是你忘记了处理列表的其余部分。基本上,您需要做的是处理集合的其余部分始终相同,并且仅根据第一个元素是否为list resp来更改处理第一个元素的方式。是否收集:
(defn d-rev [coll]
(if (empty? coll)
()
(concat (d-rev (rest coll))
(list (if (coll? (first coll))
(d-rev (first coll))
(first coll))))))
这是一个有效的解决方案。
尽管效率非常低,因为concat
完全重建了每个元素的列表。通过使用尾递归算法可以获得更好的结果,这非常简单(因为序列上的尾递归反转元素的顺序很自然):
(defn d-rev [coll]
(loop [coll coll, acc ()]
(if (empty? coll)
acc
(recur (rest coll)
(cons (if (coll? (first coll))
(d-rev (first coll))
(first coll))
acc)))))
作为最后一个建议,这里有一个解决方案,通过在更高层次上解决问题来解决另一个问题的解决方案,但它仅使用适用的核心函数reverse
和map
对序列的每个元素都有一个函数,但它本身不会深度递归:
(defn deep-reverse [coll]
(reverse (map #(if (coll? %) (deep-reverse %) %) coll)))
答案 1 :(得分:5)
您可以使用clojure.walk/postwalk
和clojure.core/reverse
构建您正在撰写的内容。这会对树输入执行深度优先遍历,并反转它找到的任何序列。
(defn dRev [lst]
(clojure.walk/postwalk #(if (seq? %) (reverse %) %) lst))
答案 2 :(得分:0)
如果输入以下内容,这是我的问题版本:
(deep-reverse '(a (b c d) 3))
返回
=> '(3 (d c b) a)
我的代码最终是这样的,但是,它们可能是更好的实现,这个工作正常。
(defn deep-reverse
"Returns the given list in reverse order. Works with nested lists."
[lst]
(cond
(empty? (rest lst)) lst
(list? (first lst)) (deep-reverse(cons (deep-reverse (first lst)) (deep-reverse (rest lst))))
:else
(concat (deep-reverse (rest lst)) (list (first lst)))))
希望这就是你要找的东西!