我一直在努力在Clojure中实现Prüfer sequence算法,主要是作为一项心理练习。虽然what I have正常工作,但我想知道是否有更简洁的方法从地图和向量集合中删除某些内容,例如,如果我想删除以下所有 5的: / p>
{1 [2 3], 2 [1 4], 3 [1 5], 4 [2], 5 [3]}
留下:
{1 [2 3], 2 [1 4], 3 [1], 4 [2]}
我怀疑我的结构是......次优......但这是我能想到的最简单的方法来表示边集。任何想法都非常感激!
答案 0 :(得分:3)
TLDR:在这种情况下使用集合代替向量。
首先,重复您选择的表示:无向图表示为从节点(由数字表示)到节点向量的映射。对于每个边 x-y ,存在从 x 到包含 y 的向量的映射条目和来自 y 到包含 x 的向量。要删除节点 z 及其所有边,必须通过删除以 z 为键的地图条目并删除 z <来维护此不变量/ em>来自所有其他条目的向量。
第一个操作 - 删除给定键的映射条目 - 很简单。没有条目的地图由表达式(dissoc m 5)
给出,其中m是示例中的地图,5是您要从图表中删除的节点。
第二个操作 - 从作为地图值的所有向量中移除元素 - 是一个复合操作,包括1)对地图的所有值执行某些操作2)从向量中移除元素。假设2)已解决(让我们称之为remove-from-vector
),我们可以通过多种方式做到1)(这里有三个例子):
(into {} (for [[k v] m]
[k (remove-from-vector v z)]))
(into {} (map (fn [[k v]]
[k (remove-from-vector v z)])
m))
(zipmap (keys m)
(map #(remove-from-vector % z) (vals m)))
问题2)提出了一些问题,因为没有内置的Clojure函数可以删除向量中间的元素。原因是矢量不能有效地发挥作用。想象一下,你有一个10000元素的向量,你想要删除索引为5000的元素。要构造新的向量,必须将4999个元素连接到包含索引0到4999的子向量的末尾。很明显,我们会最好使用能够以更好的方式处理任意元素移除的数据结构。
要解决此问题,我们可以重新设计表示。实际上有一个数据结构可以更好地处理删除:集合。如果一个集合包含具有均匀分布的哈希值的10000个值,则其内部树的高度为3.这意味着删除该集合的元素需要3个内部步骤而不是10000个数量级的内容。如果我们使用集合而不是矢量,示例地图如下所示:
{1 #{2 3}, 2 #{1 4}, 3 #{1 5}, 4 #{2}, 5 #{3}}
对于集合,与我们remove-from-vector
对应的操作为disj
- 与conj
相反。具有新表示的最终解决方案可以像这样实现:
(defn remove-node [graph node]
(into {} (for [[k v] (dissoc graph node)]
[k (disj v node)])))
答案 1 :(得分:2)
(defn my-remove [coll n]
(into (empty coll)
(map (fn [[k v]] [k (vec (remove #(= n %) v))])
(dissoc coll n))))
into
使用(empty coll)
代替{}
,以便保留记录。
答案 2 :(得分:1)
答案 3 :(得分:0)
这样的事情怎么样?
user> (def m {1 [2 3], 2 [1 4], 3 [1 5], 4 [2], 5 [3]})
#'user/m
user> (into {} (for [[k v] m] (when (not (= k 5)) [k (vec (remove (partial = 5) v))])))
{1 [2 3], 2 [1 4], 3 [1], 4 [2]}
将它包装在一个函数中,你就可以开始了。