2

这是我要运行的功能...

(defn mongean [cards times]
  (let [_cards (transient cards)]
    (loop [i 0 c (get cards i) _count (count cards) _current (/ _count 2)]
      (assoc! _cards _current c)
      (if ((rem i 2) = 0)
        (def _newcur (- _current (inc i)))
        (def _newcur (+ _current (inc i))))
      (if (<= i _count)
        (recur (inc i) (get cards i) _count _newcur )))
    (persistent! _cards)))

它导致了这个异常......

Exception in thread "main" java.lang.ClassCastException: clojure.lang.PersistentHashSet$TransientHashSet cannot be cast to clojure.lang.ITransientAssociative

作为clojure的新手,我也很感激对我上面的方法的任何建设性的批评。目标是获取一个列表,并返回一个重新排序的列表。

4

2 回答 2

8

我假设您正在尝试实现Mongean shuffle。您的方法非常必要,您应该尝试使用更实用的方法。

这将是一个可能的实现,如果我们计算卡片的最终顺序(根据 Wikipedia 公式),然后我们使用内置replace函数进行映射:

 (defn mongean [cards]
   (let [num-cards (count cards)
         final-order (concat (reverse (range 1 num-cards 2)) (range 0 num-cards 2))]
      (replace cards final-order)))

  user> (mongean [1 2 3 4 5 6 7 8])
  (8 6 4 2 1 3 5 7)
于 2012-11-24T09:57:57.250 回答
2

你怎么称呼那个函数?看起来您正在传递一个集合,因此它的瞬态版本也将是一个集合,因此不能与任何assoc函数一起使用,因为它们适用于关联数据结构和向量:

user=> (assoc #{} :a 1)
ClassCastException clojure.lang.PersistentHashSet cannot be cast to clojure.lang.Associative  clojure.lang.RT.assoc (RT.java:691)

user=> (assoc! (transient #{}) :a 1)
ClassCastException clojure.lang.PersistentHashSet$TransientHashSet cannot be cast to clojure.lang.ITransientAssociative  clojure.core/assoc! (core.clj:2959)

; the following works as it uses maps and vectors
user=> (assoc {} :a 1)
{:a 1}
user=> (assoc! (transient {}) :a 1)
#<TransientArrayMap clojure.lang.PersistentArrayMap$TransientArrayMap@65cd1dff>
user=> (assoc [] 0 :a)
[:a]

现在,让我们尝试讨论代码本身。遵循您的代码并尝试理解目标的真正含义有点困难,而无需对您想要实现的目标提供更多提示,但作为一般性评论:

  • 您有一个times根本不使用的输入参数

  • 你应该使用瞬态突变的结果,而不是假设瞬态会原地突变

  • 如果可以,请避免瞬变,它们仅用于性能优化

  • 绑定_current (/ _count 2)可能不是您想要的,因为(/ 5 2)确实返回5/2了,并且您似乎想将其用作结果中的位置

  • 常量_count不需要成为loop绑定的一部分,您可以使用外部let,这样您就不必在每次迭代时都传递它们

  • 使用let而不是def在函数中命名事物

  • (if ((rem 1 2) = 0))绝对不是你想要的

现在,抛开洗牌算法,如果你需要重新排列一个序列,你可能只需要产生一个新位置序列,map它们与原始卡片产生对,[position card]最后reduce通过将卡片放置在新位置,使用原始序列来产生对作为种子:

(defn generate [coll] ; counts down from (count coll) to 0, change to
                      ; implement your shuffling algorithm
  (range (dec (count coll)) -1 -1))

(defn mongean [cards times]
  (let [positions (generate cards) ; get the new positions
        assemble (fn [dest [pos card]] ; assoc the card at the wanted position
                   (assoc dest pos card))]
    (reduce assemble cards (map vector positions cards))))

如果你只是想洗牌:

(defn mongean [cards times] (shuffle cards))
于 2012-11-24T10:17:54.013 回答