使用 UUID 过滤其他集合的集合映射

Filter map of collection by other collection with UUID

我有以下结构

 (def my-coll '{:data (
        {:book/public-id #uuid "555b6f35-4e8c-42c5-bb80-b4d9147394c0", :book/name "AAA"}
        {:book/public-id #uuid "555b6f35-4e8c-42c5-bb80-b4d9147394c1", :book/name "BBB"}
        {:book/public-id #uuid "555b6f35-4e8c-42c5-bb80-b4d9147394c3", :book/name "CCC"}
    )} )

我想只留下来自集合的带有 id 的条目,例如按

过滤
(def filter-coll '(#uuid "555b6f35-4e8c-42c5-bb80-b4d9147394c1"  #uuid "555b6f35-4e8c-42c5-bb80-b4d9147394c2") )

我想得到

{:data (
        {:book/public-id #uuid "555b6f35-4e8c-42c5-bb80-b4d9147394c0", :book/name "AAA"}
        {:book/public-id #uuid "555b6f35-4e8c-42c5-bb80-b4d9147394c3", :book/name "CCC"}
    )}

我用 UUID 按单值过滤没有问题:

(prn {:data (filter #(= (:book/public-id %) #uuid "555b6f35-4e8c-42c5-bb80-b4d9147394c0") (my-coll :data))})

其中 my-coll 是我的输入结构。 但是当我尝试按集合过滤时

(prn {:data (filter #(contains? (:book/public-id %) filter-coll) (my-coll :data))})

我收到错误

contains? not supported on type: java.util.UUID

我可以通过集合 UUID 过滤输入结构的方法是什么?

您必须切换 contains? 的参数。这里有一个稍微更地道的版本:

(def my-coll '{:data
               ({:book/public-id #uuid "555b6f35-4e8c-42c5-bb80-b4d9147394c0"
                 :book/name "AAA"}
                 {:book/public-id #uuid "555b6f35-4e8c-42c5-bb80-b4d9147394c1"
                  :book/name "BBB"}
                 {:book/public-id #uuid "555b6f35-4e8c-42c5-bb80-b4d9147394c3"
                  :book/name "CCC"})})

;; Note I'm applying this into a set to have faster lookup.
(def filter-coll (set
                   '(#uuid "555b6f35-4e8c-42c5-bb80-b4d9147394c1"
                      #uuid "555b6f35-4e8c-42c5-bb80-b4d9147394c3")))

;; Here we use contains:
(filter #(contains? filter-coll (:book/public-id %)) (my-coll :data))

;; Here we use the fact that we can call 'sets' like functions:
(filter #(filter-coll (:book/public-id %)) (my-coll :data))

;; And an even shorter, and equivalent version with comp:
(filter (comp filter-coll :book/public-id) (:data my-coll))

首先,对于 contains? 个参数,集合应该排在第一位,您要查找的项目应该排在第二位。但即使你交换参数,这也不会按预期工作,因为 contains? 函数的行为是 a bit different.

contains? 函数仅适用于键控集合,如向量(其中键是元素索引)、集合(其中键是集合中的项)和映射。由于 filter-coll 是列表,因此 contains? 将抛出异常:

user> (contains? '(1 2 3) 1)
IllegalArgumentException contains? not supported on type: clojure.lang.PersistentList   

不过,您可以在 filter-coll 中查找所需的值,如下所示:

{:data (filter #((set filter-coll) (:book/public-id %)) (my-coll :data))}

您甚至可以考虑将 filter-coll 定义为集合。因为,filter-coll 的元素是 uuid,set 似乎很适合这里。

(def filter-coll #{#uuid "555b6f35-4e8c-42c5-bb80-b4d9147394c1"  #uuid "555b6f35-4e8c-42c5-bb80-b4d9147394c2"})

然后:

{:data (filter #(filter-coll (:book/public-id %)) (my-coll :data))}

你快到了。首先,您将 contains? 的参数顺序弄错了。所以集合先行,然后是价值。

但是 contains? 检查您传递给它的集合(第一个参数)是否包含一个键,而不是等于您传递给 contains? 的第二个参数的值,并且在列表和向量的情况下,这些键是索引:0、1、2 ...等等,所以这对您来说是无用的。

你想做的是将你的列表变成一个集合,然后就可以了。

(prn {:data (filter #(contains? (set filter-coll) (:book/public-id %)) (my-coll :data))})