(defn shuffle-letters
[word]
(let [letters (clojure.string/split word #"")
shuffled-letters (shuffle letters)]
(clojure.string/join "" shuffled-letters)))
但是如果您输入“ test”,有时可以取回“ test”。
如何修改代码以确保输出永远不会等于输入。
我感到很尴尬,我可以使用Python轻松解决它,但是Clojure对我来说是如此不同...
谢谢。
P.S。我想我们现在可以关闭主题... loop
实际上就是我所需要的...
您可以使用loop
。当改组后的字母与原始字母相同时,loop
会备份到recur
的开头:
loop
可以用多种方法编写,但是我认为这很简单。您也可以摆脱(defn shuffle-letters [word]
(let [letters (clojure.string/split word #"")]
(loop [] ; Start a loop
(let [shuffled-letters (shuffle letters)]
(if (= shuffled-letters letters) ; Check if they're equal
(recur) ; If they're equal, loop and try again
(clojure.string/join "" shuffled-letters)))))) ; Else, return the joined letters
并使loop
本身具有递归性。但是,这将导致不必要的工作。您也可以使用shuffle-letters
创建本地递归函数,但是到那时,let-fn
可能会更干净。
但注意事项:
显然,如果您尝试随机播放loop
或"H"
之类的内容,它将被卡住并永远循环播放,因为没有多少随机播放会导致它们有所不同。您可以提前进行检查,或在"HH"
中添加一个参数来限制尝试的次数。
这实际上会使您的随机播放较少随机。如果不允许它返回原始字符串,则将减少可能的输出量。
loop
的调用是不必要的。您只需在字符串上调用split
:
vec
这里是另一种解决方案(使用换能器):
vec
我们基本上创建了一个可能的混洗的惰性列表,然后我们将它们中的第一个与输入进行区别。我们还确保输入中至少包含2个不同的字符,以免挂起(由于您不想让输入字符串成为可能的结果,因此在此返回(defn shuffle-letters [word]
(let [letters (vec word)]
(loop []
(let [shuffled-letters (shuffle letters)]
(if (= shuffled-letters letters)
(recur)
(clojure.string/join "" shuffled-letters))))))
)。
如果您希望函数返回一个序列:
(defn shuffle-strict [s]
(let [letters (seq s)
xform (comp (map clojure.string/join)
(filter (fn[v] (not= v s))))]
(when (> (count (into #{} letters)) 1)
(first (eduction xform (iterate shuffle letters))))))
(for [_ (range 20)]
(shuffle-strict "test"))
;; => ("etts" "etts" "stte" "etts" "sett" "tste" "tste" "sett" "ttse" "sett" "ttse" "tset" "stte" "ttes" "ttes" "stte" "stte" "etts" "estt" "stet")
(shuffle-strict "t")
;; => nil
(shuffle-strict "ttttt")
;; => nil
nil