Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can i compare two lists by elements using Stream Java 8?

This is a simple task from some website.

If a[i] > b[i], then Alice is awarded 1 point. If a[i] < b[i], then Bob is awarded 1 point. If a[i] = b[i], then neither person receives a point. Return: Alice's score is in the first position, and Bob's score is in the second.

Can I write this code using stream?

public static List<Integer> compareTriplets(List<Integer> a, List<Integer> b) {
    int alice = 0;
    int bob = 0;
    for (int i = 0; i < a.size(); i++) {
        if (a.get(i) > b.get(i)) 
            alice++;
        else if (a.get(i) < b.get(i)) 
            bob++;
    }
    return Arrays.asList(alice, bob);
}

...

After a little thought, I wrote this code:

public static List<Integer> compareTriplets(List<Integer> a, List<Integer> b) {
    Integer[] result = {0, 0};
    IntStream.range(0, Math.min(a.size(), b.size()))
            .map(i -> a.get(i).compareTo(b.get(i)))
            .forEach(i -> {
                if (i > 0) result[0]++;
                else if (i < 0) result[1]++;
            });
    return Arrays.asList(result);
}

But this code is not much more concise. Are there ways to make the code more beautiful?

like image 659
Denis Avatar asked Feb 22 '26 12:02

Denis


2 Answers

You can make the code shorter with filter and count, but using loops is cleaner here. Streams are not always the solution.

return Arrays.asList(
    IntStream.range(0, Math.min(a.size(), b.size())).filter(i -> a.get(i) > b.get(i)).count(),
    IntStream.range(0, Math.min(a.size(), b.size())).filter(i -> a.get(i) < b.get(i)).count()
);
like image 142
Unmitigated Avatar answered Feb 24 '26 12:02

Unmitigated


Java 8 - partitioningBy() & counting()

One of the way to solve this problem with streams performing only one iteration over the given set of data is to make use of the built Collectors partitioningBy() and counting():

public static List<Integer> compareTriplets(List<Integer> a, List<Integer> b) {
    
    return IntStream.range(0, a.size())
        .map(i -> a.get(i) - b.get(i))
        .filter(i -> i != 0)
        .boxed()
        .collect(Collectors.collectingAndThen(
            Collectors.partitioningBy(i -> i > 0, Collectors.counting()),
            map -> Arrays.asList(map.get(true).intValue(), map.get(false).intValue())
        ));
}

Java 8 - custom Collector

Another option would be to define a custom Collector using static factory method Collector.of(). As well as previous approach, it would allow to process the data using a single stream:

public static List<Integer> compareTriplets(List<Integer> a, List<Integer> b) {
    
    return IntStream.range(0, a.size())
        .boxed()
        .collect(Collector.of(
            () -> new int[]{0, 0},
            (int[] score, Integer i) -> {
                if (a.get(i) > b.get(i)) score[0]++;
                if (b.get(i) > a.get(i)) score[1]++;
            },
            (int[] left, int[] right) -> {
                Arrays.setAll(left, i -> left[i] + right[i]);
                return left;
            },
            arr -> Arrays.asList(arr[0], arr[1])
        ));
}

Java 12 - Collector teeing()

Another option that would allow to produce the result using a single stream is Java 12 Collector teeing(), which expects two downstream Collectors and a Function which performs a final transformation by merging the results they produced.

public static List<Integer> compareTriplets(List<Integer> a, List<Integer> b) {
    
    return IntStream.range(0, a.size())
        .boxed()
        .collect(Collectors.teeing(
            Collectors.filtering(i -> a.get(i) > b.get(i), Collectors.counting()),
            Collectors.filtering(i -> b.get(i) > a.get(i), Collectors.counting()),
            (alice, bob) -> List.of(alice.intValue(), bob.intValue())
        ));
}
like image 22
Alexander Ivanchenko Avatar answered Feb 24 '26 11:02

Alexander Ivanchenko



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!