如何真正在Clojure中随机播放序列?

问题描述 投票:0回答:3
(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实际上就是我所需要的...

clojure shuffle
3个回答
0
投票

您可以使用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

0
投票

这里是另一种解决方案(使用换能器):

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)))))) )。


0
投票

如果您希望函数返回一个序列:

 (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
© www.soinside.com 2019 - 2024. All rights reserved.