'How to compare the elements of an ArrayList with every element of another ArrayList using Stream API of Java 8?

I have two Sorted ArrayList of same size, namely team_A & team_B, in which comparing every element of team_A with team_B to find the powerDiff > 0. After finding the powerDiff greater than 0, then removing that element from the team_B to reduce the number of iteration in the next cycle.

long calculateWin(){
    int wins = 0;
    int tempIndex=0;
    boolean flag = false;
    long powerDiff=0;

    for(int i=0; i<team_A.size(); i++) {

        for(int j=0; j<team_B.size(); j++) {

            powerDiff = team_A.get(i) - team_B.get(j);

            if(powerDiff>0) {
                wins++;
                tempIndex=j;
                flag=true;
                break;
            }

        }

        if(flag) {
            team_B.remove(tempIndex);
            flag = false;
        }

    }
    return wins;

}

The above code is working fine but due to complexity I want to optimize this code using the Stream API of Java 8.



Solution 1:[1]

Could you please try this one;

public static long calculateWinJava8(){
    List<Long> team_A = new ArrayList(Arrays.asList(50L,60L,70L,80L,90L,100L));
    List<Long> team_B = new ArrayList(Arrays.asList(30L,40L,25L,80L,55L,200L,250L));
    int wins = team_B.size();

    team_A.stream().forEach(itemA->{
         List<Long> removeItems = team_B.stream().filter(itemB-> (itemA-itemB)>0).collect(Collectors.toList());
         team_B.removeAll(removeItems);
    });

    System.out.println("result team_B : "+team_B.toString());
    wins = wins - team_B.size();
    System.out.println("wins : "+wins);
    return 0;
}

Solution 2:[2]

There isn't a good way with the standard JDK because it's lacking basic constructs like a .zip() operator and a Tuple class. If it did it would look something like this:

val wins = team_a.zip(team_b)
                .filter { tuple -> tuple.first > tuple.second }
                .count()

That's kotlin but there are a ton of java libaries that offer a .zip() and Tuple.

If you really want to do it with just the JDK it'd be something like:

long wins = IntStream
        .range(0, Math.min(team_a.size(), team_b.size()))
        .filter(i -> team_a.get(i) > team_b.get(i))
        .count();

This works but isn't ideal since you are reaching outside the pipeline unlike the first example.

Solution 3:[3]

Ok, let's untangle the logic a bit.

You check for for each pair if a[i] > b[j]. And if it matches, you remove b[j].
Good. long has a total order, so, we only need it's maximum.

long max_a = team_a.stream().mapToLong(a -> a).max().getAsLong();

Now that we have the most powerful of team a, we check how many they can defeat:

long wins = team_b.stream().filter(b -> a > b).count();

And that's it.


Wait. I did not notice the key word "sorted" in your question.
This means we can do a binary search.

First we get the maximum. I assume the list are in ascending order.

long max_a = team_a.get(team_a.size()-1);

Now we need to find where we have to make the cut:

int idx = Collections.binarySearch(team_b, max_a);

Note that Collections.binarySearch can return a negative number if the maximum is not in the list. But we are only interested in the number of smaller items in the list.

if (idx < 0)
    idx = -idx - 1

Now idx contains the number of elements smaller than the largest element in the first list. Return that:

return idx;

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 KEYSAN
Solution 2
Solution 3