【问题标题】:Get Employees before and after specific date of joining from List of Employees with Java stream使用 Java 流从员工列表中获取特定日期之前和之后的员工
【发布时间】:2020-04-21 17:05:12
【问题描述】:

我有 ListEmployees 的加入日期不同。我想在特定日期之前和之后使用流从列表中获取员工。

我尝试了以下代码,

 List<Employee> employeeListAfter = employeeList.stream()
                .filter(e -> e.joiningDate.isAfter(specificDate))
                .collect(Collectors.toList());

List<Employee> employeeListBefore = employeeList.stream()
        .filter(e -> e.joiningDate.isBefore(specificDate))
        .collect(Collectors.toList());

class Employee{
    int id;
    String name;
    LocalDate joiningDate;
}

有没有办法在单流中做到这一点?

【问题讨论】:

  • 你可以使用partitioningBy
  • 之前和之后 - 所以您想要除当天加入的员工之外的所有员工?
  • 假设它是“至少从那时起就成为员工”,你会想分成之前而不是之前,根本不关心之后。

标签: java dictionary collections java-8 java-stream


【解决方案1】:

您可以使用partitioningBy,如下所示,

Map<Boolean, List<Employee>> listMap = employeeList.stream()
        .collect(Collectors.partitioningBy(e -> e.joiningDate.isAfter(specificDate)));

List<Employee> employeeListAfter = listMap.get(true);
List<Employee> employeeListBefore = listMap.get(false);

partitioningBy 返回一个 Collector,它根据 Predicate 对输入元素进行分区,并将它们组织成一个 Map&lt;Boolean, List&lt;T&gt;&gt;

请注意,这不会处理 specificDate 的员工。

【讨论】:

  • 这不完全是,有问题的代码做了什么 - 拥有specificDate 的员工将登陆false 分区,而在有​​问题的代码中却没有
  • 添加specificDate.plusDays(1)如何解决问题? specificDate 仍将在 false 部分中。
  • @Code_Mode 你应该过滤结果列表
  • @Andronicus:只有 OP 知道这种行为是错误还是功能。对我来说,不遗漏任何员工似乎更安全。
【解决方案2】:

如果您的列表可以有条目加入specificDate,那么您可能会发现groupingBy 很有用:

Map<Integer, List<Employee>> result = employeeList.stream()
    .map(emp -> new AbstractMap.SimpleEntry<>(specificDate.compareTo(emp.getJoiningDate()), emp))
    .collect(Collectors.groupingBy(entry -> entry.getKey() > 0 ? 1 : (entry.getKey() < 0 ? -1 : 0),
            Collectors.mapping(entry -> entry.getValue(), Collectors.toList())));

employeeListAfter = result.get(-1);
employeeListBefore = result.get(1);
employeeListOnSpecificDate = result.get(0);

result 映射包含按相对于specificDate 的位置分组的Employee 记录,因此您可以选择在指定日期之前、之后或在指定日期加入的人。

【讨论】:

  • -1。您错误地假设 compareTo 只会返回 -1、0 或 1。事实上 LocalDate.compareTo 可以返回任何 int。
  • @MikeFHay 是的,here 代码如果不相等,将返回年份差。
  • @MikeFHay 感谢您指出这一点。我做了一个非常快速的测试并得出结论。更改了实现(突然看起来很复杂)。
  • @ernest_k:你可以使用原来的compareTo,然后调用Integer.signum就可以了。
  • @JollyJoker 以防万一您不知道,您可以链接到 github 中的特定行:例如 this。单击行号会直接更改 URL。如果您已经知道或不在乎,请随意忽略。 ;)
【解决方案3】:

您需要过滤掉具有此特定日期的员工。然后你可以使用分区:

Map<Boolean, List<Employee>> partitioned = employeeList.stream()
    .filter(e -> !e.joiningDate.equals(specificDate))
    .collect(partitioningBy(e -> e.joiningDate.isAfter(specificDate)));

List<Employee> employeeListAfter = partitioned.get(true);
List<Employee> employeeListBefore = partitioned.get(false);

这将根据集合是否满足谓词创建一个集合映射。

【讨论】:

  • 今天学习partitioningBy
  • 不,您不能使用日期过滤,因为它只会过滤具有特定日期的员工
【解决方案4】:

您可以使用Collectors.groupingBycompareTo 方法根据以前、当前和未来日期对员工列表进行分组

Map<Integer, List<Employee>> result = employeeList.stream()
            .collect(Collectors.groupingBy(e-> e.joiningDate.compareTo(specificDate)< 0 ? -1 : (e.joiningDate.compareTo(specificDate) == 0 ? 0 : 1)));

所以输出将是

key--> -1 ---> will have employees with previous date
key--> 0 ---> will have employees with current date
key--> 1 ---> will have employees with future date

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多