簡體   English   中英

Java Stream 比較和過濾來自 Map 的條目<string, map<string, list<string> &gt;&gt;</string,>

[英]Java Stream compare and filter entries from Map<String, Map<String, List<String>>>

我有以下 class:

 public class SomeObject {

 private String id;
 private String parentId;
 private String type;
 
 //constructor,getters,setters
 }

以及以下用例:

字段值不是唯一的。 我有一個 SomeObject 的列表。 首先我想知道哪些 SomeOjects 共享相同的 parentId,其次哪些共享相同的類型。 首先,我想將它們分組為以下結構:

 Map<String, Map<String, List<String>>>

第一個 map 的鍵是 parentId,值是另一個 map。 第二個 map 的鍵是類型,第二個 map 的值是來自 SomeObjects 的 id 列表。

我能夠做到這一點,如下所示:

    Map<String, Map<String, List<String>>> firstTry =
    SomeObjects.stream()
        .collect(
            groupingBy(
                SomeObject::getParentId,
                groupingBy(
                    SomeObject::getType,
                    mapping(SomeObject::getId, toList()))));

現在是我需要幫助的部分:

我現在想過濾這個創建的 map 如下:

假設我有 3 個 parentId 鍵,每個鍵都有一個 map 和兩個鍵:type1 和 type2。 (和 2 個 id 列表作為值)

如果 type2 的 id 列表比 type1 的 id 列表包含更多/更少/不同的 id,那么我想刪除/過濾掉它們的 parentId 條目。 我想為每個 parentId 這樣做。

流有什么辦法可以干凈地實現這一目標嗎?

在回答之前我會使用一些要點來改進代碼:

  • 我會在 map 中留下 SomeObject 指針而不是字符串文字。 它們不僅在大多數情況下效率更高(固定 8 個字節與 2 個字符字節字符串),而且訪問數據也更方便。

  • 我還將 String 類型設為枚舉類型。

但說到問題的核心,我很抱歉。

Lets assume I have 3 parentId keys which each then have a map with two keys: type1 and type2. (and 2 lists of ids as values)

{
    'p1': {
         'type1':['1','2','uuid-random-whatever'],
         'type2':['asdsad']
    },
    'p2': {
         'type1':['1','2'],
         'type2':['asdsad','i','want','more','power']
    },
    'p3': {
         'type1':['2'],
         'type2':['2']
    }
}
    

像這樣的東西

所以對於過濾本身

        Map<String, Map<String, List<String>>> theMap
                = buildMapExample();

        Predicate<Map.Entry<String, Map<String, List<String>>>> filterType2LessElementsType1 =
                (Map.Entry<String, Map<String, List<String>>> entry) ->
                        entry.getValue().get("type2").size() < entry.getValue().get("type1").size();

        Predicate<Map.Entry<String, Map<String, List<String>>>> filterType2MoreElementsType1 =
                (Map.Entry<String, Map<String, List<String>>> entry) ->
                        entry.getValue().get("type2").size() > entry.getValue().get("type1").size();

        Predicate<Map.Entry<String, Map<String, List<String>>>> filterType2SameElementsType1 =
                (Map.Entry<String, Map<String, List<String>>> entry) ->
                        (new HashSet<>(entry.getValue().get("type2")))
                                .equals(new HashSet<>(entry.getValue().get("type1")));

        theMap = theMap.entrySet().stream()
                .filter(
                        // Choose your lambda for more/less/different. for example
                        filterType2LessElementsType1
                )
                .collect(
                        Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)
                );

        printMap(theMap);

這段代碼可以工作。 我省略了建築/印刷,以免讓它變得更大。 試試看

如果您只需要保留每種類型具有相同 id 的parentId ,可以通過將 id 列表轉換為集合並檢查集合大小來完成:

List<SomeObject> list = Arrays.asList(
    new SomeObject("id1", "p1", "type1"),
    new SomeObject("id1", "p1", "type2"),

    new SomeObject("id2", "p2", "type1"),
    new SomeObject("id3", "p2", "type1"),
    new SomeObject("id2", "p2", "type2"),
            
    new SomeObject("id4", "p3", "type1"),
    new SomeObject("id4", "p3", "type2"),
    new SomeObject("id5", "p3", "type2")
);
//.. building firstTry as in the initial code snippet

System.out.println(firstTry);

firstTry.entrySet().stream()
        .filter(e -> new HashSet(e.getValue().values()).size() == 1)
        .forEach(System.out::println);

Output:

{p1={type2=[id1], type1=[id1]}, p2={type2=[id2], type1=[id2, id3]}, p3={type2=[id4, id5], type1=[id4]}}
p1={type2=[id1], type1=[id1]}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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