簡體   English   中英

Java:在兩個列表之間獲取不同的條目Map <String, Object>

[英]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個單獨的循環。 另外,您可能想使用提供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個循環,至少第二個循環可能利用了流。 您也可以在第一個循環中執行此操作,但是可能會丟失順序。 如果訂單不重要,或者您在列表末尾重新排序,那么這不是問題。

首先,您應該小心,因為該方法會對給定的參數產生副作用。 您不應修改輸入參數(此處為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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM