Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to calculate differences in a list of integers using lambda expressions

Lets say I have the following array: {1,2,3,4,6,7,8} which is put in a Stream<Integer> s = Stream.of(1,2,3,4,6,7,8);

How can I use in Java lambda expressions and Stream functions to calculate the difference between each element and the next (in this case {1,1,1,2,1,1})? This is not really a reduce operation as reduce transforms the entire list to 1 element; it also isn't a map operation as it requires two elements to calculate the difference and not just one.

like image 704
Héctor van den Boorn Avatar asked Jun 07 '15 19:06

Héctor van den Boorn


People also ask

What is lambda expression in Java 8 with example?

Lambda Expressions were added in Java 8. A lambda expression is a short block of code which takes in parameters and returns a value. Lambda expressions are similar to methods, but they do not need a name and they can be implemented right in the body of a method.

Can we use this in lambda expression?

The "this" and "super" references within a lambda expression are the same as in the enclosing context. Since the lambda expression doesn't define a new scope, "this" keyword within a lambda expression signifies "this" parameter of a method where the lambda expression is residing.


2 Answers

You can use my StreamEx library which has a pairMap method specially for this case:

StreamEx<Integer> s = StreamEx.of(1,2,3,4,6,7,8);
s = s.pairMap((a, b) -> b-a);
s.forEach(System.out::println);

The StreamEx class implements Stream and is fully compatible with it. The same thing works with primitive streams as well:

IntStreamEx s = IntStreamEx.of(1,2,3,4,6,7,8);
s = s.pairMap((a, b) -> b-a);
s.forEach(System.out::println);
like image 153
Tagir Valeev Avatar answered Oct 01 '22 09:10

Tagir Valeev


The other answer seems to be accepted already, but had an idea so I post it anyway. You can make a Collector that collects it directly to another Stream<Integer>.

Then you can just write like:

s.collect(intDifferences()).forEach(d -> System.out.print(d + ","));

Here's an implementation I wrote:

public static Collector<Integer, List<Integer>, Stream<Integer>> intDifferences() {

    return new Collector<Integer, List<Integer>, Stream<Integer>>() {

        @Override
        public BiConsumer<List<Integer>, Integer> accumulator() {
            return List::add;
        }

        @Override
        public Set<Collector.Characteristics> characteristics() {
            return EnumSet.noneOf(Collector.Characteristics.class);
        }

        @Override
        public BinaryOperator<List<Integer>> combiner() {
            return (left, right) -> {
                left.addAll(right);
                return left;
            };
        }

        @Override
        public Function<List<Integer>, Stream<Integer>> finisher() {
            return list -> {
                List<Integer> differences = new ArrayList<>();
                for (int i = 1; i < list.size(); i++) {
                    differences.add(list.get(i) - list.get(i - 1));
                }
                return differences.stream();
            };
        }

        @Override
        public Supplier<List<Integer>> supplier() {
            return ArrayList::new;
        }
    };
}
like image 26
Bubletan Avatar answered Oct 01 '22 11:10

Bubletan