簡體   English   中英

Java 8使用流和收集器映射到集合的子列表條目

[英]Java 8 mapping to sub list entries of a collection using streams and collectors

我有一個Person對象的集合:

public class Person {

  String name;

  ChildrenListHolder childrenListHolder;
}

public class ChildrenListHolder {
   List<Children> children;
}

public class Children {
   String childrensName;
}

(實體結構由第三方提供。)

現在,我需要一個Map<String,List<Person>> childrensName - > person-list

例如(簡化):

Person father: {name: "John", childrensListHolder -> {"Lisa", "Jimmy"}}
Person mother: {name: "Clara", childrensListHolder -> {"Lisa", "Paul"}}
Person george: {name: "George", childrensListHold -> "Paul"}}

我需要的地圖是

Map<String, List<Person>> map: {"Lisa"  -> {father, mother},
                                "Jimmy" -> {father},
                                "Paul"  -> {mother, george}}

我可以用一堆for和if來做到這一點。 但是我如何使用流和收集器來做到這一點。 我嘗試了很多方法,但是我無法得到預期的結果。 TIA。

給定List<Person> persons ,您可以擁有以下內容

Map<String,List<Person>> map =
    persons.stream()
           .flatMap(p -> p.childrenListHolder.children.stream().map(c -> new AbstractMap.SimpleEntry<>(c, p)))
           .collect(Collectors.groupingBy(
             e -> e.getKey().childrensName,
             Collectors.mapping(Map.Entry::getValue, Collectors.toList())
           ));

這正在為人們創造一條流。 然后每個人通過一個元組來平面映射,該元組持有孩子和每個孩子的人。 最后,我們按子名稱分組並將所有人員收集到一個列表中。

假設有適當的構造函數的示例代碼:

public static void main(String[] args) {
    List<Person> persons = Arrays.asList(
        new Person("John", new ChildrenListHolder(Arrays.asList(new Children("Lisa"), new Children("Jimmy")))),
        new Person("Clara", new ChildrenListHolder(Arrays.asList(new Children("Lisa"), new Children("Paul")))),
        new Person("George", new ChildrenListHolder(Arrays.asList(new Children("Paul"))))
    );

    Map<String,List<Person>> map =
        persons.stream()
               .flatMap(p -> p.childrenListHolder.children.stream().map(c -> new AbstractMap.SimpleEntry<>(c, p)))
               .collect(Collectors.groupingBy(
                 e -> e.getKey().childrensName,
                 Collectors.mapping(Map.Entry::getValue, Collectors.toList())
               ));

    System.out.println(map);
}

我可以用一堆for和if來做到這一點。

我知道你要求一個流/收集器解決方案,但無論如何使用Map#computeIfAbsent的嵌套for循環也可以Map#computeIfAbsent工作:

Map<String, List<Person>> map = new HashMap<>();
for(Person p : persons) {
    for(Children c : p.childrenListHolder.children) {
        map.computeIfAbsent(c.childrensName, k -> new ArrayList<>()).add(p);
    }
}

這是使用集合中引入的新forEach方法編寫的:

Map<String, List<Person>> map = new HashMap<>();
persons.forEach(p -> p.childrenListHolder.children.forEach(c -> map.computeIfAbsent(c.childrensName, k -> new ArrayList<>()).add(p)));

當然,它不是單線程,也不像Tunaki的解決方案(+1)那樣易於並行化,但是你也不需要“束”來實現它(並且你也避免創建臨時的映射條目實例)。

暫無
暫無

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

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