我想创建一个散列图,其中 n 以3个为一组创建的键值对,其中集合不相交,例如[(34 false) (35 false) (36 false)] && [(24 false) (25 false) (26 false)] -> {34 false 35 false 36 false 24 false 25 false 26 false}
修改
为了与Clojure一起玩/练习,我试图实现战舰棋盘游戏的惯用版本。我决定将战舰坐标存储在哈希映射中,其中键是坐标,值是布尔值,表示该部分是否已被击中。下面的具体代码是假设到
为此,我已经创建了以下代码。它有两个问题:
执行该功能会导致使用' acc'累加器:
clojure.lang.LazySeq无法转换为clojure.lang.Associative
该函数的结果不是单个哈希映射,而是 n 哈希映射列表
使用惯用语法,我如何实现目标?
(defn launch
[n]
(loop [cnt n acc {}]
(if (= cnt 0)
acc
(recur
(- cnt 1)
((fn []
(let [axis (rand-int 2)]
(if (= axis 0)
(let [x (rand-int 8) y (rand-int 10)]
(for [k (range 3)]
(assoc acc (str y (+ x k)) false)))
(let [x (rand-int 10) y (rand-int 8)]
(for [k (range 3)]
(assoc acc (str (+ y k) x) false)))))))))))
答案 0 :(得分:3)
我将如何重写它:
(defn create-key [axis-val i]
(if axis-val
(str (rand-int 10) (+ (rand-int 8) i))
(str (+ (rand-int 8) i) (rand-int 10))))
(defn launch [n]
(reduce (fn [acc axis]
(reduce #(assoc % (create-key axis %2) false)
acc
(range 3)))
{}
(repeatedly n #(zero? (rand-int 2)))))
在repl中:
user> (launch 5)
{"40" false, "07" false, "19" false,
"46" false, "87" false, "47" false,
"41" false, "62" false, "86" false}
或(如果您不喜欢reduce
):
(defn launch [n]
(zipmap (mapcat #(map (partial create-key %) (range 3))
(repeatedly n #(zero? (rand-int 2))))
(repeat false)))
第三个变体是使用列表推导来生成密钥:
(defn launch [n]
(zipmap (for [_ (range n)
:let [axis (zero? (rand-int 2))]
i (range 3)]
(create-key axis i))
(repeat false)))
所有这三个都是惯用的,我猜,所以根据你自己喜欢的编程风格,你可以自己选择一个。
请注意,生成的键会在地图中进行混洗,因为未排序的地图不会保留顺序。如果重要,您应该使用sorted-map
您的变体怎么样,产生错误的一个是:
(for [k (range 3)] (assoc acc (str y (+ x k)) false))
它没有将所有键放到一张地图上,而是生成一个等于(assoc acc k false)
的三个项目的序列:
(let [acc {}]
(for [k (range 3)] (assoc acc k false)))
;;=> ({0 false} {1 false} {2 false})
要做你想做的事,你可以使用reduce
:
(let [acc {}]
(reduce #(assoc %1 %2 false) acc (range 3)))
;;=> {0 false, 1 false, 2 false}
答案 1 :(得分:0)
首先,我不确定你为什么要重新绑定一个匿名函数调用的值。您的let
会愉快地返回结果;所以,你应该考虑为什么你认为有必要创建一个匿名函数。
其次,问题是for
返回一个懒惰的seq,并且你将它绑定到你认为的地图数据结构。这解释了为什么它适用于0和1的情况,但是当你使用值2时它会失败。
由于我并不完全了解您要完成的任务,因此这是您的原始代码,经过修改即可使用。免责声明 - 这不是真正的惯用,也不是我写的方式,但是我发帖是因为看起来与原作相比可能会有所帮助,因为它确实有用。
(defn launch
[n]
(loop [cnt n
acc {}]
(if (= cnt 0)
acc
(recur
(dec cnt)
(into acc
(let [axis (rand-int 2)]
(if (= axis 0)
(let [x (rand-int 8) y (rand-int 10)]
(map #(hash-map (str y (+ x %)) false) (range 3)))
(let [x (rand-int 10) y (rand-int 8)]
(map #(hash-map (str (+ y %) x) false) (range 3))))))))))