Map<String, List<Employee>> myMap = new HashMap<>(); for (int j = 0; j < (MAX_SALARY - MIN_SALARY) / value; j++) { List<Employee> list = new ArrayList<>(); for (Employee emp : employees) { if (emp.getSalary() >= (j + 1) * value && emp.getSalary() < (j + 2) * value) list.add(emp); } myMap.put(Integer.toString((j + 1) * value) + "-" + Integer.toString((j + 2) * value), list); } for (String key : myMap.keySet()) { System.out.println(key + " -> " + myMap.get(key).size()); } 

    2 answers 2

    So, the task is to create a Map from the list of employees, the key of which is the salary interval, and the value is the list of employees whose salaries fall into this interval.

    Let's try to start to realize this "naively." Cycle

     for (int j = 0; j < (MAX_SALARY - MIN_SALARY) / value; j++) 

    can be replaced by IntStream :

     IntStream.range(0, (MAX_SALARY - MIN_SALARY) / value) 

    Employees whose salary is included in the interval [(j + 1) * value, (j + 2) * value) , can be distinguished as follows:

     employees .stream() .filter(e -> e.getSalary() >= (j + 1) * value && e.getSalary() < (j + 2) * value) .collect(Collectors.toList()) 

    You can add them to the Map using Collectors.toMap() :

     Collectors.toMap( i -> (j + 1) * value + "-" + (j + 2) * value, i -> employees .stream() .filter(e -> e.getSalary() >= (j + 1) * value && e.getSalary() < (j + 2) * value) .collect(Collectors.toList())) 

    Putting it all together, we get

     Map<String, List<Employee>> map = IntStream.range(0, (MAX_SALARY - MIN_SALARY) / value) .boxed() // Нужно, чтобы перейти от IntStream // к обычному Stream, в котором доступна // нужная нам перегрузка метода collect() .collect(Collectors.toMap( i -> (i + 1) * value + "-" + (i + 2) * value, i -> employees .stream() .filter(e -> e.getSalary() >= (i + 1) * value && e.getSalary() < (i + 2) * value) .collect(Collectors.toList()))); 

    We clean up a bit and optimize the code:

     Map<String, List<Employee>> map = IntStream.range(0, (MAX_SALARY - MIN_SALARY) / value) .map(i -> (i + 1) * value) .boxed() .collect(Collectors.toMap( i -> i + "-" + (i + value), i -> employees .stream() .filter(e -> e.getSalary() >= i) .filter(e -> e.getSalary() < i + value) .collect(Collectors.toList()))); 

    Done! Now go to the documentation and read about Collectors.groupingBy() . Taking into account what we read, we rewrite our code like this:

     Map<String, List<Employee>> map = employees.stream() .collect(Collectors.groupingBy( e -> e.getSalary() / value * value + "-" + (e.getSalary() / value + 1) * value)); 

    e.getSalary() / value * value and (e.getSalary() / value + 1) * value allows you to determine the boundaries of the interval in which the salary falls. Due to integer division, e.getSalary() / value * value not necessarily equal to e.getSalary() .

    We get almost the same result as in the original. Almost - because there are no ranges that no employee falls into. We correct this misunderstanding:

     Map<String, List<Employee>> map = employees.stream() .filter(e -> e.getSalary() >= MIN_SALARY && e.getSalary() <= MAX_SALARY) .collect(Collectors.groupingBy(e -> e.getSalary() / value * value + "-" + (e.getSalary() / value + 1) * value)); IntStream.range(0, (MAX_SALARY - MIN_SALARY) / value) .map(i -> (i + 1) * value) .mapToObj(i -> i + "-" + (i + value)) .filter(key -> !map.containsKey(key)) .forEach(key -> map.put(key, Collections.emptyList())); 

    Everything, now the result is exactly the same as in the original.

    However, I advise you to think twice before rewriting the code in this way. Usually, streams are used to increase the readability of the code, to describe what you want to do, and not how . In this case, I do not observe an increase in readability; on the contrary, the code becomes more confusing. Stream rewriting works well when processing a collection in one cycle, but nested loops on streams are harder to read.

    • In the source code, the outer loop is used only for grouping, so IntStream is not needed. - Sergey Gornostaev
    • Therefore, I called the first implementation "naive" - ​​stupid rewriting of the loop. This is later rewritten via Collectors.groupingBy() . - fori1ton
    • Thank you for the detailed response - Alexandr Buyanov pm
    • code earned, great ..... - Alexandr Buyanov

    As far as I understand your code, you are trying to get the number of employees by salary ranges.

     Map<String, Long> map = employees.stream() .map(Employee::getSalary) .collect(Collectors.groupingBy( salary -> ((salary + 1) * value) + "-" + ((salary + 2) * value), Collectors.counting())) 
    • Thanks for the help - Alexandr Buyanov