![](/img/trans.png)
[英]How to map different values from 2 sets in clojure based on unique value
[英]clojure - update map values in different ways based on key value
我想在棋盘游戏中用Clojure表示2D位置+邻居的图形。 我正在使用将位置映射到邻居矢量的地图:
{[0 0] [[0 1] [1 0] [1 1]]}
我编写了一些函数,可以为任何大小的板生成邻居图:
(defn positions [size]
(for [x (range 0 size) y (range 0 size)] [x y]))
(defn neighbors [size [x y]]
(filter (fn [[x y]]
(and (>= x 0) (< x size) (>= y 0) (< y size)))
(-> []
(conj [(inc x) y])
(conj [(dec x) y])
(conj [x (inc y)])
(conj [x (dec y)])
(conj [(inc x) (inc y)])
(conj [(dec x) (dec x)]))))
(defn board-graph
[size]
(reduce (fn [map position] (assoc map
position
(neighbors size position)))
{}
(positions size)))
这工作正常:
(board-graph 2)
=> {[0 0] ([1 0] [0 1] [1 1]), [0 1] ([1 1] [0 0]), [1 0] ([0 0] [1 1] [0 0]), [1 1] ([0 1] [1 0] [0 0])}
但是,我现在想在板边缘上的每个板位置上添加此额外的“虚拟邻居”,例如.TOP,:BOTTOM,:LEFT,:RIGHT。 所以我想:
(board-graph 2)
=> {[0 0] (:LEFT :TOP [1 0] [0 1] [1 1]), [0 1] (:LEFT :BOTTOM [1 1] [0 0]), [1 0] (:RIGHT :TOP [0 0] [1 1] [0 0]), [1 1] (:RIGHT :BOTTOM [0 1] [1 0] [0 0])}
到目前为止,这是我的尝试,但效果不佳,似乎过于复杂:
(defn- filter-keys
[pred map]
(into {}
(filter (fn [[k v]] (pred k)) map)))
(defn board-graph
[size]
(let [g (reduce (fn [map position] (assoc map
position
(neighbors size position)))
{}
(positions size))]
(merge g
(reduce-kv #(assoc %1 %2 (conj %3 :TOP)) {}
(filter-keys (fn [[x y]] (= y 0)) g))
(reduce-kv #(assoc %1 %2 (conj %3 :BOTTOM)) {}
(filter-keys (fn [[x y]] (= y (dec size))) g))
(reduce-kv #(assoc %1 %2 (conj %3 :LEFT)) {}
(filter-keys (fn [[x y]] (= x 0)) g))
(reduce-kv #(assoc %1 %2 (conj %3 :RIGHT)) {}
(filter-keys (fn [[x y]] (= x (dec size))) g)))))
我基本上想构建我的地图,再次遍历它,并且对于某些键,根据键是什么,在那里更新关联的值。 不求助于状态,我找不到一个很好的方法! 有没有更惯用的方法呢?
您可以在创建返回的矢量的线程表达式中添加一些表达式。 为了使此内容更好看,我将其从线程第一个宏->
切换为“线程为”宏as->
,该宏将符号c(在这种情况下)绑定到每个步骤中要线程化的值,因此可以在在某些阶段的条件表达式:
(defn neighbors [size [x y]]
(filter (fn [[x y]]
(and (>= x 0) (< x size) (>= y 0) (< y size)))
(as-> [] c
(conj c [(inc x) y])
(conj c [(dec x) y])
(conj c [x (inc y)])
(conj c [x (dec y)])
(conj c [(inc x) (inc y)])
(conj c [(dec x) (dec x)])
(if (zero? x) (conj c :TOP) c)
(if (= size x) (conj c :BOTTOM) c)
(if (zero? y) (conj c :LEFT) c)
(if (= size y) (conj c :RIGHT) c))))
每个条件表达式要么返回更新的版本,要么在不满足条件的情况下通过更新版本。
这对我有用,但是与您最初编写的内容不太接近。
(defn positions [size]
(for [x (range 0 size) y (range 0 size)] [x y]))
(defn neighbors [n [x y]]
(let [left (if (zero? x)
:LEFT
[(dec x) y])
right (if (= x (dec n))
:RIGHT
[(inc x) y])
up (if (zero? y)
:TOP
[x (dec y)])
down (if (= y (dec n))
:BOTTOM
[x (inc y)])]
(list left right up down)))
(defn board-graph [n]
(let [keys (positions n)
vals (map (partial neighbors n) keys)]
(zipmap keys vals)))
然后
(clojure-scratch.core/board-graph 2)
=>
{[1 1] ([0 1] :RIGHT [1 0] :BOTTOM),
[1 0] ([0 0] :RIGHT :TOP [1 1]),
[0 1] (:LEFT [1 1] [0 0] :BOTTOM),
[0 0] (:LEFT [1 0] :TOP [0 1])}
编辑:正如亚瑟(Arthur)指出的那样,如果您愿意的话,这不会处理对角线。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.