如何使用 Java 流 API 基于 属性 对元素进行分组

How to group elements based their property using Java Stream API

我有一个自然数列表。如何使用 Java Stream API?

对所有可被 3、5 和两者整除的数字进行分组

例如:

ArrayList<Integer> list = new ArrayList<>();
list.add(24);
list.add(25);
list.add(45);
list.add(30);
list.add(3);
list.add(20);
list.add(5);

我想要 l3 = [3,24] , l5 = [5,20,25], l35 = [45,30]

此外,我不想在列表中调用 groupingBy() 三次,因为列表真的很大。

我会使用辅助枚举来描述数字的不同可能分类,并结合 Collectors.groupingBy():

import java.util.*;
import java.util.stream.*;

public class Demo {

    private enum Fizzbuzz {
        DIV_BY_THREE, DIV_BY_FIVE, DIV_BY_BOTH, DIV_BY_NEITHER;

        static public Fizzbuzz classify(int i) {
            if (i % 3 == 0) {
                return i % 5 == 0 ? DIV_BY_BOTH : DIV_BY_THREE;
            } else if (i % 5 == 0) {
                return DIV_BY_FIVE;
            } else {
                return DIV_BY_NEITHER;
            }
        }
    }

    public static void main(String[] args) {
        List<Integer> list = List.of(24, 25, 45, 30, 3, 20, 5);
        Map<Fizzbuzz, List<Integer>> groups =
            list.stream().collect(Collectors.groupingBy(Fizzbuzz::classify));
        System.out.println(groups);
    }
}

产出

{DIV_BY_THREE=[24, 3], DIV_BY_FIVE=[25, 20, 5], DIV_BY_BOTH=[45, 30]}

缩减为地图

使用streams reduction。 这里我们可以使用 reduce(identityFunc, accumulationFunc, combiningFunc) 变体:

初始映射包含 4 个 String 键映射到空 List<Integer>:

  1. "I" 对于所有未映射的(非 fizz-buzz-able)整数
  2. "I3" 可被 3 整除
  3. "I5" 可被 5 整除
  4. "I35" 可被 3 和 5 整除

runnable demo on IDEone:

Map<String, List<Integer>> fizzBuzz = new HashMap<>(3);
fizzBuzz.put("I", new ArrayList());
fizzBuzz.put("I3", new ArrayList());
fizzBuzz.put("I5", new ArrayList());
fizzBuzz.put("I35", new ArrayList());

list.stream().reduce(
       fizzBuzz,
       (map, e) -> {
          String key = "I"; // default key
          if (e % 3 == 0) key = "I3";
          if (e % 5 == 0) key = "I5";
          if (e % (3*5) == 0) key = "I35";
          map.get(key).add(e);
          return map;
        },
        (m, m2) -> {
            m.putAll(m2);
            return m;
        }
    );
        
System.out.println(fizzBuzz);

打印预期的:

{I=[], I3=[24, 3], I35=[45, 30], I5=[25, 20, 5]}

另请参阅: