Java:在两个列表Map <string,object =“”>之间获取不同的条目

时间:2017-02-07 10:02:36

标签: java

我有两个列表Map。我希望基于Object的某些字段获得它们之间的不同条目。我创建了一个方法如下:

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"] }

2 个答案:

答案 0 :(得分:1)

我还不熟悉Java 8流,但您的方法可以进行优化(如我的评论中所述),因此更容易被重构为流。

首先,您不应该使用嵌套循环,而是使用2个单独的循环。此外,您可能希望使用提供IDID1的特殊密钥对象以及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个循环,至少第二个循环可能会使用流。您也可以为第一个循环执行此操作,但您可能会丢失排序。如果订单不重要或者您在最后重新排序列表,这不是问题。

答案 1 :(得分:0)

首先,您应该小心,因为该方法对给定参数有副作用。你不应该修改输入参数(这里是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(...

然后,您必须提取将元素移除到synchronized方法的语句,因为此方法将被异步调用。

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));