Is there a way to coalesce repeated numbers in a list using streams in Java 8?

后端 未结 3 1082
长发绾君心
长发绾君心 2021-02-06 12:06

e.g.#1 [1, 1, 1, 2, 22, 35, 35, 120, 320] ==>> [3, 2, 22, 70, 120, 320]

note how repeated consecutive 1\'s and 35\'s are coalesced to 3 and 70

相关标签:
3条回答
  • 2021-02-06 12:54
    Stream.of(1, 1, 1, 2, 22, 35, 35, 120, 320)
              .collect(Collectors.toMap(
                  Function.identity(),
                  Function.identity(),
                  Integer::sum,
                  LinkedHashMap::new
              ))
              .values()
              .forEach(System.out::println);
    

    In the case the you posted a comment, you would need a custom collector, actually:

    static class Custom implements Collector<Integer, List<Integer>, List<Integer>> {
    
        private Integer match;
    
        @Override
        public Supplier<List<Integer>> supplier() {
            return ArrayList::new;
        }
    
        @Override
        public BiConsumer<List<Integer>, Integer> accumulator() {
            return (list, x) -> {
                int lastIndex = list.size() - 1;
                if (match != null && match.equals(x)) {
                    list.set(lastIndex, list.get(lastIndex) + x);
                } else {
                    match = x;
                    list.add(x);
                }
            };
        }
    
        @Override
        public BinaryOperator<List<Integer>> combiner() {
            return (left, right) -> {
                throw new RuntimeException("Not for parallel");
            };
        }
    
        @Override
        public Function<List<Integer>, List<Integer>> finisher() {
            return Function.identity();
        }
    
        @Override
        public Set<Characteristics> characteristics() {
            return Set.of();
        }
    }
    

    And usage would be:

    public static void main(String[] args) {
        Stream.of(1, 1, 3, 1, 1)
              .collect(new Custom())
              .forEach(System.out::println);
    }
    
    0 讨论(0)
  • 2021-02-06 13:00

    Here is an approach using a stack.

    public static List<Integer> coalesce(List<Integer> list) {
        Stack<Integer> stack = new Stack<>();
        stack.addAll(list);
        List<Integer> sums = new ArrayList<>();
        int sum = 0;
        while (!stack.isEmpty()) {
           int val = stack.pop();
           sum += val;
           if (!stack.isEmpty() && stack.peek() != val) {
              sums.add(0,sum);
              sum = 0;
           }
        }
        sums.add(0,sum);
        return sums;
    }
    
    0 讨论(0)
  • 2021-02-06 13:05

    Why bother using streams when you can do it with a simple for loop and an if-else block?

       List<Integer> list = List.of(0, 0, 0, 0, 1, 1, 1, 0, 0, 0);
       List<Integer> result = new ArrayList<>();
       Integer curr = list.get(0);
       Integer sum = 0;
       for(Integer i : list){
           if(i.equals(curr)){
               sum += i;
           }
           else{
               result.add(sum);
               sum = i;
               curr = i;
           }
       }
       result.add(sum);
       System.out.println(result);
    
    0 讨论(0)
提交回复
热议问题