该函数接受一组数字向量,并返回它们的交集:
(defn foo [& sets] (apply clojure.set/intersection (map #(set %) sets)))例如:
user=> (foo [1 2 3] [3 4 5 1] [33 3 3 1])
#{1 3}如果输入集的元素是具有:id键作为映射的唯一属性的映射,那么如何实现相同的功能呢?
即。我正在编写一个函数foo2,它执行以下操作:
user=> (foo2 [{:id 1 ...} {:id 2 ...} {:id 3 ...}]
[{:id 3 ...} {:id 4 ...} {:id 5 ...} {:id 1 ...}]
[{:id 33 ...} {:id 3 ...} {:id 3 ...} {:id 1 ...}])
[{:id 1 ...} {:id 3 ...}]有什么简单的方法吗?
或者是收集in、获取键的交集、然后在输入集中查找键的唯一方法?
是否有任何方法通过定义返回任意对象键的“键值”函数来“重载”集合函数(联合、交叉等),或者是否只能使用带有原语值的集合?
发布于 2016-04-26 15:32:58
编辑:我以前错误地假设具有相同:id的映射保证具有相同的键和值。如果允许他们有所不同,这是一个更好的答案:
(defn intersect-by [key-fn data]
(let [normalized (map (fn [map-data]
(->> map-data
(group-by key-fn)
(map (fn [[key val]]
[key (apply merge val)]))
(into {})))
data)
normalized-keys (map (comp set keys) normalized)
intersection (apply clojure.set/intersection normalized-keys)
merged-data (apply merge-with merge normalized)]
(vals (select-keys merged-data intersection))))
#'user/foo
(def data [[{:id 1} {:id 2} {:id 3, :x 3}]
[{:id 3, :y 4} {:id 4} {:id 5} {:id 1}]
[{:id 33} {:id 3} {:id 3, :z 5} {:id 1}]])
#'user/data
(intersect-by :id data)
({:id 1} {:id 3, :x 3, :y 4, :z 5})如果您假设两个具有相同:id的映射被保证具有相同的键和值,那么您的第一个foo函数已经这样做了:
(def data [[{:id 1} {:id 2} {:id 3}]
[{:id 3} {:id 4} {:id 5} {:id 1}]
[{:id 33} {:id 3} {:id 3} {:id 1}]])
#'user/data
(defn foo [& sets] (apply clojure.set/intersection (map #(set %) sets)))
#'user/foo
(apply foo data)
#{{:id 1} {:id 3}}发布于 2016-04-26 14:13:00
在将每个向量转换为由clojure.set/intersection设置的排序后,我将做几乎相同的操作::id
user> (defn intersect [& colls]
(apply clojure.set/intersection
(map #(apply sorted-set-by
(fn [{id1 :id} {id2 :id}] (compare id1 id2))
%)
colls)))
#'user/intersect
user> (intersect [{:id 1} {:id 2} {:id 3}]
[{:id 3} {:id 4} {:id 5} {:id 1}]
[{:id 33} {:id 3} {:id 3} {:id 1}])
#{{:id 1} {:id 3}}注意,这种方法将使用相同的:id值处理不同的映射,但我想这正是您所需要的。顺便说一句,sorted-set正是您想要的“重载”设置函数的方式。
您可以使一个助手函数看起来更通用:
user> (defn key-comparator [key]
#(compare (key %1) (key %2)))
#'user/key-comparator
user> (defn intersect [& colls]
(apply clojure.set/intersection
(map #(apply sorted-set-by (key-comparator :id) %)
colls)))
#'user/intersect
user> (intersect [{:id 1} {:id 2} {:id 3 :x 1}]
[{:id 3 :x 10} {:id 4} {:id 5} {:id 1}]
[{:id 33} {:id 3 :x 33} {:id 3 :x 2} {:id 1}])
#{{:id 1} {:id 3, :x 33}}另一个变体是过滤第一个coll中的所有项,其id存在于所有其他coll中:
user> (defn intersect-2 [c & cs]
(if (empty? cs) c
(filter (fn [{id :id :as itm}]
(every? (partial some #(when (= id (:id %)) %))
cs))
c)))
#'user/intersect-2
user> (intersect-2 [{:id 1} {:id 2} {:id 3 :x 1}]
[{:id 3 :x 10} {:id 4} {:id 5} {:id 1}]
[{:id 33} {:id 3 :x 33} {:id 3 :x 2} {:id 1}])
({:id 1} {:id 3, :x 1})https://stackoverflow.com/questions/36867070
复制相似问题