如何将Stream<Person>分组为Stream<List<Person>>而非Map<String,List<Person>>
问题解答
方案1:基于现有分组逻辑快速实现(底层用Map,无需显式维护Map变量)
该方案实现最简单、性能稳定,时间复杂度为O(n),是绝大多数场景的最优选择。底层虽然用Map做分组,但你不需要手动维护Map实例,也不需要处理分组key,完全满足「不需要保留分组key」的需求:
Stream<List<Person>> resultStream = persons.stream() .collect(Collectors.groupingBy(Person::getName)) .values() .stream();
方案2:完全不使用Map实现(需保证同name元素连续)
如果要求全程不使用Map集合,可以实现,但需要满足「相同name的Person元素在列表中连续排列」的前提:
- 如果原始列表没有这个特性,需要先按
name属性排序,会引入O(nlogn)的排序性能开销 - 如果原始列表已经保证同name元素连续,可以直接跳过排序步骤,时间复杂度为O(n)
JDK原生实现示例:
// 1. 先按name排序(原始列表已满足同name连续可删除此步骤) List<Person> sortedPersons = persons.stream() .sorted(Comparator.comparing(Person::getName)) .toList(); // 2. 拆分连续同name的元素为独立列表 Stream<List<Person>> resultStream = Stream.iterate(0, i -> i < sortedPersons.size(), i -> { String currentName = sortedPersons.get(i).getName(); int end = i; while (end < sortedPersons.size() && sortedPersons.get(end).getName().equals(currentName)) end++; return end; }).map(i -> { String currentName = sortedPersons.get(i).getName(); int end = i; while (end < sortedPersons.size() && sortedPersons.get(end).getName().equals(currentName)) end++; return sortedPersons.subList(i, end); });
你也可以通过自定义Collector实现更优雅的连续分组逻辑,避免重复遍历判断下标。
内容的提问来源于stack exchange,提问作者Oleg Sandro
相关产品推荐
相关产品推荐

