Java流 – 通过嵌套列表分组(按第二顺序列出)
我有以下数据结构 –
每个学生的名单,每个学生都拥有一个国家名单,每个国家都有一份城市名单。
public class Student { private int id; private String name; private List states = new ArrayList(); } public class State { private int id; private String name; private List Cities = new ArrayList(); } public class City { private int id; private String name; }
我想得到以下内容。
Map citiesIdsToStudensList;
我写了以下内容
Map<Integer, List> statesToStudentsMap = students.stream() .flatMap(student -> student.getStates().stream()) .flatMap(state -> state.getCities().stream()) .collect(Collectors.groupingBy(City::getId, Collectors.mapping(x -> x.getId(), Collectors.toList())));
但它并没有让我得到我想要的结果。
使用Stream API,您需要平面地图两次,并将每个中间学生和城市映射到一个能够抓住学生的元组。
Map> citiesIdsToStudentsList = students.stream() .flatMap(student -> student.getStates().stream().map(state -> new AbstractMap.SimpleEntry<>(student, state))) .flatMap(entry -> entry.getValue().getCities().stream().map(city -> new AbstractMap.SimpleEntry<>(entry.getKey(), city))) .collect(Collectors.groupingBy( entry -> entry.getValue().getId(), Collectors.mapping(Map.Entry::getKey, Collectors.toList()) ));
但是,在这里使用嵌套for
循环可能更简洁:
Map> citiesIdsToStudentsList = new HashMap<>(); for (Student student : students) { for (State state : student.getStates()) { for (City city : state.getCities()) { citiesIdsToStudentsList.computeIfAbsent(city.getId(), k -> new ArrayList<>()).add(student); } } }
这利用computeIfAbsent
填充地图并创建具有相同城市ID的每个学生的列表。
除了Tunaki的答案 ,你可以简化它
Map> citiesIdsToStudentsList = students.stream() .flatMap(student -> student.getStates().stream() .flatMap(state -> state.getCities().stream()) .map(state -> new AbstractMap.SimpleEntry<>(student, state.getId()))) .collect(Collectors.groupingBy( Map.Entry::getValue, Collectors.mapping(Map.Entry::getKey, Collectors.toList()) ));
它利用了一个事实,即您实际上并不对State
对象感兴趣,因此如果您在第一个flatMap
操作中正确执行它,则可以将它们直接flatMap
到所需的City
对象。 然后,通过在创建Map.Entry
时立即执行State.getId
操作,可以简化实际的collect
操作。