【问题标题】:Filter map of collection by other collection with UUID使用 UUID 按其他集合过滤集合的映射
【发布时间】:2016-05-18 16:01:09
【问题描述】:

我有以下结构

 (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 过滤输入结构?

【问题讨论】:

    标签: clojure uuid


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      首先,对于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))}
      

      【讨论】:

        【解决方案3】:

        你快到了。首先,您将contains? 的参数顺序错误。所以先收藏,再看价值。

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

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

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

        【讨论】:

          猜你喜欢
          • 2016-02-25
          • 1970-01-01
          • 2016-08-01
          • 2015-07-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多