Java 使用流中的重复元素创建多个列表

Java create multiple lists with duplicate elements from stream

我正在尝试获取一个列表 return 一个 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());

这是执行您想要的操作的示例代码。不需要多个流,仅一个流就足以遍历对象。

        Map<String, List<String>> result = new HashMap<>();
        result.put("fname", new ArrayList<String>());
        result.put("lname", new ArrayList<String>());
        result.put("fullTime", new ArrayList<String>());
        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));
        employees.forEach(e -> {
            result.get("fname").add(e.firstName);
            result.get("lname").add(e.lastName);
            result.get("fullTime").add(e.firstName + " " + e.lastName);
        });
        System.out.println(result);

我会留给你将列表转换为不可变列表。

我建议你把生成列表的每个流都放在方法中。像这样:

public static List<String> getListFirstName(List<Employee> employees) {
    return   employees.stream()
            .map(e -> e.getFirstName())
            .collect(Collectors.toUnmodifiableList());
}

public static List<String> getListLasttName(List<Employee> employees) {
    return  employees.stream()
            .map(e -> e.getLastName())
            .collect(Collectors.toUnmodifiableList());
}

public static List<String> getListFullTime(List<Employee> employees) {
    return  employees.stream()
            .filter(e -> e.getStatus().equals(Status.FULL_TIME))
            .map(e -> e.getFirstName()+" "+e.getLastName())
            .collect(Collectors.toUnmodifiableList());
}

public static List<String> getListPartTime(List<Employee> employees) {
    return  employees.stream()
            .filter(e ->e.getStatus().equals(Status.PART_TIME))
            .map(e -> e.getFirstName()+" "+e.getLastName())
            .collect(Collectors.toUnmodifiableList());
}

创建一个方法,该方法 return 一个 Map,它采用员工列表和字符串条件来生成 Map(键是条件,值是包含想要的列表数据):

public static Map<String, List<String>> getByCriteria(String criteria , List<Employee> employees) {
    Map<String, List<String>>map =  new HashMap<>();
    
    if("fName".equals(criteria)) {
        map.put(criteria, getListFirstName(employees));
    }else if("lName".equals(criteria)) {
        map.put(criteria, getListFirstName(employees));
    }else if("fullTime".equals(criteria)) {
        map.put(criteria, getListFullTime(employees));
    }else if("partTime".equals(criteria)) {
        map.put(criteria, getListPartTime(employees));
    }
    return Collections.unmodifiableMap(map);
}

创建标准列表,例如:

    List<String> criterias = List.of("fName", "lName", "fullTime", "partTime");

从条件列表创建流以生成包含您想要的内容的最终地图

Map<String, List<String>> collect = criterias.stream().parallel().map(c -> getByCriteria(c , employees)).flatMap(map -> map.entrySet().stream())
        .collect(Collectors.toMap(eM -> eM.getKey(), eM -> eM.getValue())); 

这里是完整的 class:

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Main {

    public static void main(String[] args) {
        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));
        List<String> criterias = List.of("fName", "lName", "fullTime", "partTime");
        
        Map<String, List<String>> collect = criterias.stream().parallel().map(c -> getByCriteria(c , employees)).flatMap(map -> map.entrySet().stream())
        .collect(Collectors.toMap(eM -> eM.getKey(), eM -> eM.getValue()));
        
        System.out.println(collect);
        

    }
    
    public static Map<String, List<String>> getByCriteria(String criteria , List<Employee> employees) {
        Map<String, List<String>>map =  new HashMap<>();
        
        if("fName".equals(criteria)) {
            map.put(criteria, getListFirstName(employees));
        }else if("lName".equals(criteria)) {
            map.put(criteria, getListFirstName(employees));
        }else if("fullTime".equals(criteria)) {
            map.put(criteria, getListFullTime(employees));
        }else if("partTime".equals(criteria)) {
            map.put(criteria, getListPartTime(employees));
        }
        return Collections.unmodifiableMap(map);
    }
    
    public static List<String> getListFirstName(List<Employee> employees) {
        return   employees.stream()
                .map(e -> e.getFirstName())
                .collect(Collectors.toUnmodifiableList());
    }
    
    public static List<String> getListLasttName(List<Employee> employees) {
        return  employees.stream()
                .map(e -> e.getLastName())
                .collect(Collectors.toUnmodifiableList());
    }
    
    public static List<String> getListFullTime(List<Employee> employees) {
        return  employees.stream()
                .filter(e -> e.getStatus().equals(Status.FULL_TIME))
                .map(e -> e.getFirstName()+" "+e.getLastName())
                .collect(Collectors.toUnmodifiableList());
    }
    
    public static List<String> getListPartTime(List<Employee> employees) {
        return  employees.stream()
                .filter(e ->e.getStatus().equals(Status.PART_TIME))
                .map(e -> e.getFirstName()+" "+e.getLastName())
                .collect(Collectors.toUnmodifiableList());
    }

}

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

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())));

然而,此解决方案的内存消耗比我 中的解决方案差,特别是在处理大流时。

既然你说你可以使用 apache commons,也许是这样的?

    Map<String, List<String>> map = new HashMap<>();
    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));

    List<String> firstNames = new ArrayList<>();
    List<String> lastNames = new ArrayList<>();
    List<String> ftEmployees = new ArrayList<>();

    employees.forEach(employee -> {
        firstNames.add(employee.firstName);
        lastNames.add(employee.lastName);
        if (employee.status == Status.FULL_TIME) {
            ftEmployees.add(employee.firstName + " " + employee.lastName);
        }
    });

    map.put("fname", ImmutableList.copyOf(firstNames));
    map.put("lName", ImmutableList.copyOf(lastNames));
    map.put("fullTime", ImmutableList.copyOf(ftEmployees));

这是一个示例,但您将添加一些额外的行和第三行 class。

主要

var 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)
);

var maps = employees.stream()
        .flatMap(employee -> Stream.of(
                new Pair("fName", employee.firstName),
                new Pair("lName", employee.lastName),
                new Pair(
                        employee.status == Status.FULL_TIME ? "fullTime" : "partTime",
                        employee.firstName.concat(" ").concat(employee.lastName)
                )
        ))
        .filter(pair -> !pair.name.equals("partTime"))
        .collect(Collectors.groupingBy(
                pair -> pair.name,
                Collectors.mapping(pair -> pair.value, Collectors.toUnmodifiableList())
        ));

相关classes

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

    //constructors, setters and getters
}

enum Status {
    FULL_TIME,
    PART_TIME
}

class Pair {
    String name;
    String value;

    //constructors, setters and getters
}