【问题标题】:Retrieving list of employees with lowest salary using stream [duplicate]使用流检索薪水最低的员工列表[重复]
【发布时间】:2019-09-13 12:30:55
【问题描述】:

我正在尝试从员工列表中检索薪水最低的人员列表。到目前为止,我已经设法找到薪水最低的 员工,但如果有几名员工的薪水相同,我想检索多个员工。

我认为解决方案应该是一行。所以我不能创建一个薪水最低的变量,只检查每个变量的“薪水低于或等于 Low_Salary”。我试过了,效果很好。

所以我相信我的问题是“.min(比较器)”只检索最低的一个。

Comparator<Employee> comparator = Comparator.comparing( Employee :: getSalary);
List<Employee> lowSalary = employees.stream()
               .min(comparator)
               .stream()
               .collect(Collectors.toList());
lowSalary.forEach(System.out::println);

【问题讨论】:

标签: java lambda java-8 java-stream


【解决方案1】:

首先创建一个TreeMap,其key是工资。 TreeMap 按其键对其条目进行排序。然后获取第一个条目,即薪水最低的条目并获取与之相关的值。此解决方案仅对列表进行一次迭代。这是它的外观。

List<Employee> empsWithLowestSalary = employees.stream()
    .collect(Collectors.groupingBy(Employee::getSalary, TreeMap::new, Collectors.toList()))
    .firstEntry()
    .getValue();

TreeMap 将地图元素存储在红黑树中。红黑树中一个元素的插入成本为O(Log (n))。由于我们要插入n 元素,因此该解决方案的总时间复杂度为O(n Log (n))。对于firstEntry(),它需要恒定的时间O(1),因为它分别维护一个指向树中最左边和最右边叶子节点的指针。最左边的节点代表树中的最小值,而最右边的叶子节点代表最高值。

通过关注great answer,我想到了编写一个自定义收集器来满足我们的目的。该收集器仅对 List 进行一次迭代,其运行时复杂度为 O(n),明显优于上述方法。此外,它允许您在一个语句中编写您的客户端代码。这是它的外观。

static <T> Collector<T, ?, List<T>> minList(Comparator<? super T> comp) {
    return Collector.of(ArrayList::new, (list, t) -> {
        int c;
        if (list.isEmpty() || (c = comp.compare(t, list.get(0))) == 0)
            list.add(t);
        else if (c < 0) {
            /*
             * We have found a smaller element than what we already have. Clear the list and
             * add this smallest element to it.
             */
            list.clear();
            list.add(t);
        }
    }, (list1, list2) -> {
        if (comp.compare(list1.get(0), list2.get(0)) < 0)
            return list1;
        else if (comp.compare(list1.get(0), list2.get(0)) > 0)
            return list2;
        else {
            list1.addAll(list2);
            return list1;
        }
    });
}

这是您的客户端代码。

Collection<Employee> empsWithLowestSalary = employees.stream()
                .collect(minList(Comparator.comparing(Employee::getSalary)));

【讨论】:

  • 这个解决方案的复杂性是什么?我相信它是 O(n*logn)。
  • 对,就是排序算法的代价。
  • 不错的答案。除了时间复杂度之外,在我看来,这个解决方案还会为groupingBy 收集器消耗额外的空间。
  • 空间复杂度为 O(n),因为我们在这里存储了 n 个地图条目。
【解决方案2】:

您可以按工资分组,然后检索最低工资的员工列表:

List<Employee> employees = new ArrayList<Employee>(){{
    add(new Employee("bilbo baggins", 10));
    add(new Employee("frodo baggins", 10));
    add(new Employee("gandalf grey", 100));
}};

Map<Integer, List<Employee>> result = employees.stream().collect(groupingBy(Employee::getSalary));

List<Employee> allMin = result.entrySet().stream()
        .min(Comparator.comparing(Map.Entry::getKey))
        .map(Map.Entry::getValue)
        .orElse(Collections.emptyList());

allMin.forEach(System.out::println);

输出

Employee{name='bilbo baggins', salary=10}
Employee{name='frodo baggins', salary=10}

【讨论】:

    【解决方案3】:
    Integer lowestSalary = employees.stream()
    .min(Comparator.comparing(Employee::getSalary))
    .map(Employee::getSalary).get();
    
    List<Employee> employeesWithLowestSalary = employees.stream()
    .filter(e -> e.getSalary() == lowestSalary)
    .collect(Collectors.toList());
    

    首先查找最低工资是多少,然后过滤员工列表,以便您只有工资匹配的员工。

    【讨论】:

      【解决方案4】:

      你可以先得到最低工资的员工,然后按它过滤,

        Comparator<Employee> comparator = Comparator.comparing( Employee :: getSalary);
              Optional<Employee> min = employees.stream()
                      .min(comparator);
              List<Employee> lowSalary = employees.stream()
                      .filter(ele->ele.salary==min.get().salary)
                      .collect(Collectors.toList());
      

      【讨论】:

        【解决方案5】:

        您可以先计算最低工资,然后在您的Stream#filtercondition 中使用它:

        int salary = 
           employees.stream()
                    .min(Comparator.comparing(Employee::getSalary))
                    .map(e -> e.getSalary())
                    .orElse(-1);
        
        List<Employee> emps = 
          employees.stream()
                   .filter(emp -> emp.getSalary() == salary)
                   .collect(Collectors.toList());
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-01-07
          • 1970-01-01
          • 2016-07-24
          • 1970-01-01
          • 2014-02-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多