Clojure 从向量中删除值的引用

Clojure 从向量中删除值的引用,clojure,Clojure,我一直在努力在Clojure中实现一个算法,主要是作为一种心理练习。虽然工作正常,但我想知道是否有更简洁的方法从地图和向量集合中删除某些内容,例如,如果我想删除以下所有5个: {1[23],2[14],3[15],4[2],5[3]} 留下: {1[23],2[14],3[1],4[2]} 我怀疑我的结构是。。。次优。。。但这是我能想到的表示边集的最简单方法。任何想法都非常感谢 像这样的怎么样 user> (def m {1 [2 3], 2 [1 4], 3 [1 5], 4 [2],

我一直在努力在Clojure中实现一个算法,主要是作为一种心理练习。虽然工作正常,但我想知道是否有更简洁的方法从地图和向量集合中删除某些内容,例如,如果我想删除以下所有5个:

{1[23],2[14],3[15],4[2],5[3]}

留下:

{1[23],2[14],3[1],4[2]}


我怀疑我的结构是。。。次优。。。但这是我能想到的表示边集的最简单方法。任何想法都非常感谢

像这样的怎么样

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]}
只需将其包装在函数中,就可以开始了。

用于从映射中删除键及其值

对于读者或您的代码(阅读:maintainer)来说,它的含义更清楚,并且它的实现可能更快

对于向量和集合,您必须坚持使用remove;没有等效的函数来删除值

 (defn my-remove [coll n]
    (into (empty coll) 
      (map (fn [[k v]] [k (vec (remove #(= n %) v))]) 
           (dissoc coll n))))

into
使用
(空coll)
代替
{}
,以便保存记录。

TLDR:在这种情况下使用集合而不是向量。

首先,重复您选择的表示:无向图表示为从节点(由数字表示)到节点向量的映射。对于每个边x–y,存在一个从x到包含y的向量的映射条目,以及一个从y到包含x的向量的条目。要删除节点z及其所有边,必须通过删除以z为键的贴图条目以及从所有其他条目的向量中删除z来保持此不变量

第一个操作——根据地图条目的键删除它——很简单。表达式
(dissoc m 5)
给出了不带条目的映射,其中m是示例中的映射,5是希望从图中删除的节点

第二个操作——从作为映射值的所有向量中删除元素——是一个复合操作,包括1)对映射的所有值执行操作2)从向量中删除元素。假设2)已解决(我们称之为
从向量中移除
),我们可以通过多种方式(这里有三个示例)实现1):

问题2)提出了一些问题,因为没有内置的Culjule函数去除向量中间的元素。原因是,这不是一个向量可以有效地做的事情。假设您有一个包含10000个元素的向量,并且希望删除索引为5000的向量。要构造新的向量,4999个元素必须与包含索引0到4999的子向量的末尾相连。显然,我们最好使用一种能够更好地处理任意元素移除的数据结构

为了解决这个问题,我们可以重新设计表示。事实上,有一种数据结构可以更好地处理删除:集合。如果一个集合包含10000个具有均匀分布散列值的值,则其内部树的高度为3。这意味着删除集合中的一个元素需要3个内部步骤,而不是10000数量级的步骤。如果我们使用集合而不是向量,示例地图如下所示:

{1 #{2 3}, 2 #{1 4}, 3 #{1 5}, 4 #{2}, 5 #{3}}
(defn remove-node [graph node]
  (into {} (for [[k v] (dissoc graph node)]
             [k (disj v node)])))
对于集合,与上面的
remove from vector
相对应的操作是
disj
–与
conj
相反。具有新表示形式的最终解决方案可以如下实现:

{1 #{2 3}, 2 #{1 4}, 3 #{1 5}, 4 #{2}, 5 #{3}}
(defn remove-node [graph node]
  (into {} (for [[k v] (dissoc graph node)]
             [k (disj v node)])))

非常感谢你的建议!我按照你的建议改变了结构,并更新了要点。所有伟大的建议,其中一些我已经能够纳入。Raek得到了它,因为相邻的边确实需要存储在一个集合中,正如他指出的那样。