java小技巧(四)--利用lambada 对list进行分组汇总

对一个List进行分组汇总的lambada写法:

list.stream().collect(Collectors.groupingBy(TestDTO::getId, Collectors.summarizingInt(TestDTO::getValue)));

 

上面TestDTO::getValue是进行整形汇总,但是如果TestDTO::getValue是BigDecimal类型的怎么办,写法如下:
list.stream().collect(Collectors.groupingBy(TestDTO::getId, Collectors.reducing(BigDecimal.ZERO, TestDTO::getValue, BigDecimal::add)));

 

多个list合并成一个list

比如有下面数据结构:

        List<List<String>> list = new ArrayList<>();

        List<String> sub1 = new ArrayList<>();
        sub1.add("1111");
        sub1.add("2222");
        sub1.add("3333");
        sub1.add("4444");
        list.add(sub1);

        List<String> sub2 = new ArrayList<>();
        sub2.add("aaaa");
        sub2.add("bbbb");
        sub2.add("cccc");
        sub2.add("dddd");
        list.add(sub2);

        List<String> sub3 = new ArrayList<>();
        sub3.add("a001");
        sub3.add("b002");
        sub3.add("c003");
        sub3.add("d004");
        list.add(sub3);

合并成一个List的写法:

List<String> myList = list.stream().flatMap(Collection::stream).collect(Collectors.toList());


求平均值:
list.stream().collect(Collectors.groupingBy(TestDTO::getId, Collectors.averagingInt(TestDTO::getValue)));
如果TestDTO::getValue是BigDecimal类型的,则不能这么用,需要自己写一个工具类:
1 @FunctionalInterface
2 public interface ToBigDecimalFunction<T> {
3 
4     BigDecimal applyAsBigDecimal(T value);
5 }

 

  1 public final class CustomCollectors {
  2 
  3     private static final Set<Collector.Characteristics> CH_NOID = Collections.emptySet();
  4 
  5     private CustomCollectors() {}
  6 
  7 
  8     @SuppressWarnings("unchecked")
  9     private static <I, R> Function<I, R> castingIdentity() {
 10         return i -> (R) i;
 11     }
 12 
 13     /**
 14      * Simple implementation class for {@code Collector}.
 15      *
 16      * @param <T> the type of elements to be collected
 17      * @param <R> the type of the result
 18      */
 19     @SuppressWarnings("hiding")
 20     static class CollectorImpl<T, A, R> implements Collector<T, A, R> {
 21         private final Supplier<A> supplier;
 22         private final BiConsumer<A, T> accumulator;
 23         private final BinaryOperator<A> combiner;
 24         private final Function<A, R> finisher;
 25         private final Set<Characteristics> characteristics;
 26 
 27         CollectorImpl(Supplier<A> supplier,
 28                       BiConsumer<A, T> accumulator,
 29                       BinaryOperator<A> combiner,
 30                       Function<A,R> finisher,
 31                       Set<Characteristics> characteristics) {
 32             this.supplier = supplier;
 33             this.accumulator = accumulator;
 34             this.combiner = combiner;
 35             this.finisher = finisher;
 36             this.characteristics = characteristics;
 37         }
 38 
 39         CollectorImpl(Supplier<A> supplier,
 40                       BiConsumer<A, T> accumulator,
 41                       BinaryOperator<A> combiner,
 42                       Set<Characteristics> characteristics) {
 43             this(supplier, accumulator, combiner, castingIdentity(), characteristics);
 44         }
 45 
 46         @Override
 47         public BiConsumer<A, T> accumulator() {
 48             return accumulator;
 49         }
 50 
 51         @Override
 52         public Supplier<A> supplier() {
 53             return supplier;
 54         }
 55 
 56         @Override
 57         public BinaryOperator<A> combiner() {
 58             return combiner;
 59         }
 60 
 61         @Override
 62         public Function<A, R> finisher() {
 63             return finisher;
 64         }
 65 
 66         @Override
 67         public Set<Characteristics> characteristics() {
 68             return characteristics;
 69         }
 70     }
 71 
 72     //求和方法
 73     public static <T> Collector<T, ?, BigDecimal> summingBigDecimal(ToBigDecimalFunction<? super T> mapper) {
 74         return new CollectorImpl<>(
 75                 () -> new BigDecimal[]{new BigDecimal(0)},
 76                 (a, t) -> { a[0] = a[0].add(mapper.applyAsBigDecimal(t), MathContext.DECIMAL32); },
 77                 (a, b) -> { a[0] = a[0].add(b[0], MathContext.DECIMAL32) ; return a; },
 78                 a -> a[0], CH_NOID);
 79     }
 80 
 81 
 82     //求最大,这里的最小MIN值,作为初始条件判断值,如果某些数据范围超过百亿以后,可以根据需求换成Long.MIN_VALUE或者Double.MIN_VALUE
 83     public static <T> Collector<T, ?, BigDecimal> maxBy(ToBigDecimalFunction<? super T> mapper) {
 84         return new CollectorImpl<>(
 85                 () -> new BigDecimal[]{new BigDecimal(Integer.MIN_VALUE)},
 86                 (a, t) -> { a[0] = a[0].max(mapper.applyAsBigDecimal(t)); },
 87                 (a, b) -> { a[0] = a[0].max(b[0]) ; return a; },
 88                 a -> a[0], CH_NOID);
 89     }
 90 
 91     //求最小,这里的最大MAX值,作为初始条件判断值,如果某些数据范围超过百亿以后,可以根据需求换成Long.MAX_VALUE或者Double.MAX_VALUE
 92     public static <T> Collector<T, ?, BigDecimal> minBy(ToBigDecimalFunction<? super T> mapper) {
 93         return new CollectorImpl<>(
 94                 () -> new BigDecimal[]{new BigDecimal(Integer.MAX_VALUE)},
 95                 (a, t) -> { a[0] = a[0].min(mapper.applyAsBigDecimal(t)); },
 96                 (a, b) -> { a[0] = a[0].min(b[0]) ; return a; },
 97                 a -> a[0], CH_NOID);
 98     }
 99 
100     /**
101      * 返回一个平均值
102      * @param newScale 保留小数位数
103      * @param roundingMode 小数处理方式
104      *     #ROUND_UP 进1
105      *     #ROUND_DOWN 退1
106      *     #ROUND_CEILING  进1截取:正数则ROUND_UP,负数则ROUND_DOWN
107      *     #ROUND_FLOOR  退1截取:正数则ROUND_DOWN,负数则ROUND_UP
108      *     #ROUND_HALF_UP >=0.5进1
109      *     #ROUND_HALF_DOWN >0.5进1
110      *     #ROUND_HALF_EVEN
111      *     #ROUND_UNNECESSARY
112      */
113     //求平均,并且保留小数
114     public static <T> Collector<T, ?, BigDecimal> averagingBigDecimal(ToBigDecimalFunction<? super T> mapper, int newScale, int roundingMode) {
115         return new CollectorImpl<>(
116                 () -> new BigDecimal[]{new BigDecimal(0),new BigDecimal(0)},
117                 (a, t) -> { a[0] = a[0].add(mapper.applyAsBigDecimal(t)); a[1] = a[1].add(BigDecimal.ONE); },
118                 (a, b) -> { a[0] = a[0].add(b[0]) ; return a; },
119                 a -> a[0].divide(a[1],MathContext.DECIMAL32).setScale(newScale,roundingMode), CH_NOID);
120     }
121 }

 那么针对BigDecimal类型的求平均值可以写成如下:

1 Map<Integer, BigDecimal> result1 = list.stream().collect(Collectors.groupingBy(TestDTO::getId, CustomCollectors.averagingBigDecimal(TestDTO::getValue, 2, ROUND_DOWN)));

 

posted on 2022-08-17 11:14  小夏coding  阅读(5031)  评论(0编辑  收藏  举报

导航