Clojure瞬态 - 结合!造成例外

时间:2012-11-24 07:19:30

标签: list clojure shuffle

这是我正在尝试运行的功能......

(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不熟悉,我也很欣赏对我上述方法的任何建设性批评。目标是获取一个List,并返回一个重新排序的列表。

2 个答案:

答案 0 :(得分:8)

我假设您正在尝试实施Mongean shuffle。您的方法非常迫切,您应该尝试使用更实用的方法。

这是一个可能的实现,如果我们计算卡的最终顺序(根据维基百科公式),然后我们使用内置的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)

答案 1 :(得分: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对,最后{ {1}}将卡片放在新位置,使用原始序列作为种子:

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