[英]Merge two lists of objects into Map having value as different object in java 8
[英]Java: Get different entries between two lists Map<String, Object>
我有两个列表Map。 我想基于对象的某些字段在它们之间获取不同的条目。 我创建了如下方法:
private List<Map<String,Object>> GetDifferentEntries(List<Map<String,Object>> setA, List<Map<String,Object>> setB) {
List<Map<String,Object>> tmp = new ArrayList<Map<String,Object>>(setA);
for(Map<String,Object> a : tmp){
for(Map<String,Object> b: setB){
if(a.get("ID").equals(b.get("ID")) && a.get("ID1").equals(b.get("ID1")) ){
setA.remove(a);
}
} }return setA;}
我可以在Java 8中使用Stream类再次编写上述方法吗?
我有一个例子:
List1={ [ID=1, actor="A", ID1 = 1, film="F"],
[ID=2, actor="B", ID1 = 1, film="F"],
[ID=3, actor="C", ID1 = 1, film="F"]}
List2={ [ID=1, director="A", ID1 = 1, film="F"],
[ID=5, director="E", ID1 = 1, film="F"]}
Result = { [ID=2, actor="B", ID1 = 1, film="F"],
[ID=3, actor="C", ID1 = 1, film="F"] }
我还不太熟悉Java 8流,但是可以优化您的方法(正如我的评论中所述),因此可以更容易地将其重构为流。
首先,您不应使用嵌套循环,而应使用2个单独的循环。 另外,您可能想使用提供ID
和ID1
的特殊键对象以及hashCode()
和equals()
适当实现。 例:
class Key {
String id;
String id1;
int hashCode() { ... }
boolean equals(Object o) { ... }
}
然后为第一个列表构建一个LinkedHashMap
(您可以使用HashMap
但是那样可以保留元素顺序):
Map<Key, Map<String, Object>> mapA = new LinkedHashMap<>();
for( for(Map<String,Object> a : setA){
mapA.put( new Key( a.get("ID"), a.get("ID1") ), a );
}
请注意,这是假设您的列表中不包含重复项,如果重复,那么您需要做的略有不同(但我会留给您)。
现在您已经有了setA
的映射,可以消除setB
中包含的元素了:
for(Map<String,Object> b: setB){
//if the key is not present nothing will be removed
mapA.remove( new Key( b.get("ID"), b.get("ID1") ) );
}
最终根据mapA
建立了一个列表:
List<Map<String,Object>> prunedSetA = new ArrayList<>( mapA.values() );
如您所见,您现在有2个循环,至少第二个循环可能利用了流。 您也可以在第一个循环中执行此操作,但是可能会丢失顺序。 如果订单不重要,或者您在列表末尾重新排序,那么这不是问题。
首先,您应该小心,因为该方法会对给定的参数产生副作用。 您不应修改输入参数(此处为setA)。
您的副本不够深。 您创建了一个临时列表。 那没问题。 但是,请勿复制条目,因为这将导致修改的输入参数(通过引用而不是通过值)产生副作用。 调用者将输入参数传递给您的方法后,无法相信它们是相同的。 如果要避免副作用,则还必须复制地图。 除此之外,您只应从副本中删除元素。
接下来,仅处理SetA中元素的情况。 SetB中不在SetA中的元素无法识别。 这个对吗?
private List<Map<String, Object>> getDifferentEntries(List<Map<String, Object>> setA, List<Map<String, Object>> setB) {
List<Map<String, Object>> result = makeDeepCopyOf(setA);
setA.stream().forEach((entryA) -> {
setB.stream().forEach((entryB) -> {
if (entryA.get("ID").equals(entryB.get("ID")) && entryA.get("ID1").equals(entryB.get("ID1"))) {
result.remove(entryA);
}
});
});
return result;
}
要使用并行性,可以使用并行流。 它将加载您的CPU,而无需关心线程处理:
setA.stream().parallel().forEach(...
setB.stream().parallel().forEach(...
然后,您必须提取将元素删除到同步方法的语句,因为该方法将被异步调用。
private synchronized removeElementFrom(List<Map<String, Object>> list, Map<String, Object> entry) {
list.remove(entry);
}
或者,您考虑将setA的副本包装到合适的同步数据结构中:
List<Map<String, Object>> result = Collections.synchronizedList(makeDeepCopyOf(setA));
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.