首页 > 解决方案 > Java从流中创建具有重复元素的多个列表

问题描述

我正在尝试获取一个列表并返回一个Map<String, List<String>包含原始列表某些方面的列表,其中原始元素可能使用流作为不同键下的值多次出现。例如:

class Employee {
  String firstName;
  String lastName;
  Status status;
}

enum Status {
  FULL_TIME,
  PART_TIME
}

List<Employee> employees = List.of(
  new Employee("f1", "l1", Status.PART_TIME),
  new Employee("f2", "l2", Status.FULL_TIME),
  new Employee("f3", "l3", Status.PART_TIME),
  new Employee("f4", "l4", Status.FULL_TIME));

生成的映射应具有如下键,并且列表必须是不可变的:

fName: ["f1", "f2", "f3", "f4"],
lName: ["l1", "l2", "l3", "l4"],
fullTime: ["f2 l2", "f4 l4"]

这对于多个流来说很容易,但是原始数据非常大,所以我试图一次性完成。如果有另一种我不知道的方法,我也可以使用 Guava 和 Apache Commons。谢谢!

编辑1:展示我现在的表现

这是我在三个流中所做的事情,我想简化为一个:

var firstName = employees.stream()
        .map(e -> e.getFirstName())
        .collect(Collectors.toUnmodifiableList());
var lastName = employees.stream()
        .map(e -> e.getLastName())
        .collect(Collectors.toUnmodifiableList());
var fullTime = employees.stream()
        .filter(e -> e.getStatus().equals(Status.FULL_TIME))
        .collect(Collectors.toUnmodifiableList());

标签: javajava-streamjava-11

解决方案


您可以将员工对象转换为对列表,其中对键是映射键,对值是列表的单个值。然后您可以通过键“分组”对。

Map<String, List<String>> vals = employees.stream()
  .map(e -> Arrays.asList(
    Pair.of("fname", e.firstName),
    Pair.of("lname", e.lastName),
    e.status == Status.FULL_TIME ? Pair.of("fullTime", e.firstName + " " + e.lastName) : null
  ))
  .flatMap(Collection::stream)
  .filter(Objects::nonNull)
  .collect(Collectors.groupingBy(p -> p.getLeft(), 
           Collectors.mapping(p -> p.getRight(), Collectors.toUnmodifiableList())));

但是,此解决方案的内存消耗比我之前的答案中的要差,特别是在处理大流时。


推荐阅读