Java 两张地图的区别
我需要非常有效地比较Clojure/Java中的两个映射,并返回由Java的.equals(..)确定的差异,其中nil/null相当于“notpresent” i、 e.我正在寻找编写函数的最有效方法,如:Java 两张地图的区别,java,algorithm,clojure,hashmap,Java,Algorithm,Clojure,Hashmap,我需要非常有效地比较Clojure/Java中的两个映射,并返回由Java的.equals(..)确定的差异,其中nil/null相当于“notpresent” i、 e.我正在寻找编写函数的最有效方法,如: (map-difference {:a 1, :b nil, :c 2, :d 3} {:a 1, :b "Hidden", :c 3, :e 5}) => {:b nil, :c 2, :d 3, :e nil} 我更喜欢一个不可变的Clojure映射作为输出,但是如果
(map-difference
{:a 1, :b nil, :c 2, :d 3}
{:a 1, :b "Hidden", :c 3, :e 5})
=> {:b nil, :c 2, :d 3, :e nil}
我更喜欢一个不可变的Clojure映射作为输出,但是如果性能得到显著改善,Java映射也可以
值得一提的是,我的基本测试用例/行为预期是,对于任意两个映射a和b,以下内容将是相等的(直到null=“Not present”的等价性):
a
(merge b (difference a b))
实现这一点的最佳方式是什么
在Java中,Google Commons Collections提供了一个非常好的解决方案。使用内置的Collections API:
Set<Map.Entry<K,V>> difference = a.entrySet().removeAll(b.entrySet());
Set difference=a.entrySet().removeAll(b.entrySet());
如果需要将其转换回映射,则必须进行迭代。在这种情况下,我建议:
Map<K,V> result = new HashMap<K,V>(Math.max(a.size()), b.size()));
Set<Map.Entry<K,V>> filter = b.entrySet();
for( Map.Entry<K,V> entry : a.entrySet ) {
if( !filter.contains( entry ) {
result.put(entry.getKey(), entry.getValue());
}
}
Map result=newhashmap(Math.max(a.size()),b.size());
Set filter=b.entrySet();
for(Map.Entry:a.entrySet){
如果(!filter.contains)(条目){
put(entry.getKey(),entry.getValue());
}
}
我不确定最有效的方法是什么,但以下几点可能很有用:
a
和b
是映射,使得b
至少包含一个a
中不存在的键,(合并b)
不能等于a
PersistentHashMap
,那么
(clojure.lang.PersistentHashMap/create
(doto (java.util.HashMap.)
(.put :foo 1)
(.put :bar 2)))
; => {:foo 1 :bar 2}
(.keySet {:foo 1 :bar 2})
; => #< [:foo, :bar]>
我认为在大多数情况下,仅仅做(concat(key m1)(key m2))
并可能复制一些工作可能比在每一步检查“其他映射”中的给定键更有效我不确定它的性能
(defn map-difference
[orig other]
(let [changed (set/difference (set orig) (set other))
added (set/difference (set (keys other)) (set (keys orig)))]
(reduce (fn [acc key]
(assoc acc key :missing))
(into {} changed)
added)))
我使用了:missing
键来避免原始地图中的nil
值与缺失键之间的歧义——当然,您可以将其更改为nil
,,您也可以使用谷歌番石榴库中的方法,那么
(defn map-diff [m1 m2]
;; m1: hashmap
;; m2: hashmap
;; => the difference between them
(reduce merge
(map #(hash-map % (- (or (% m1) 0) (or (% m2) 0)))
(keys (merge m1 m2)))))
谢谢这是有用的,尽管比我要找的更一般(它产生了一整套地图比较,而不是我要找的简单差异地图),请修正第三点的语法;这没有道理。回答得太好了,迈克尔,非常感谢!关于1)只有一点,如果您指定nil相当于不存在(根据问题),我认为可以通过将map difference指定nil给需要“删除”的键来满足要求。希望您知道def记录?如果您不需要tha地图是通用的,那么这可能是一个解决方案。@mikera:谢谢,很高兴听到这个消息。:-)对于1),这是一个很好的观点,对任何解决方案来说都应该是一个小小的调整——感谢您的更正@尼克:我不知道你在想什么。你能详细说明一下吗?@Michal Marczyk-你的第一个优雅的基线解决方案发生了什么?我想看一看,但它现在不见了。@Adam Schmideg:我发现它与规格不符,于是把它删掉了。你可以在这个答案的修订历史中看到它(链接到“编辑的某某某某时间前”通知的“某某某某时间前”部分,就在答案文本下面)。老故事,但我想知道clojure 1.3中的
clojure.data.diff
对你的问题会有什么影响?
(defn map-difference
[orig other]
(let [changed (set/difference (set orig) (set other))
added (set/difference (set (keys other)) (set (keys orig)))]
(reduce (fn [acc key]
(assoc acc key :missing))
(into {} changed)
added)))
(defn map-diff [m1 m2]
;; m1: hashmap
;; m2: hashmap
;; => the difference between them
(reduce merge
(map #(hash-map % (- (or (% m1) 0) (or (% m2) 0)))
(keys (merge m1 m2)))))