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

时间:2016-05-18 16:01:10

标签: clojure 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过滤输入结构的方式是什么?

3 个答案:

答案 0 :(得分:2)

您必须切换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))

答案 1 :(得分:1)

首先,对于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定义为set。因为filter-coll的元素是uuids,所以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))}

答案 2 :(得分:1)

你几乎就在那里。首先,你得到了contains?的参数顺序错误。所以收集首先是价值,然后是价值。

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

你想要做的是将你的列表变成一个集合,这就是它。

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