Is there a more efficient Java 8 Stream approach for finding an index in int []?

Based on the BlackJack Question , I wondered how to indicate all the winning hands. The initial question simply asked, in fact, about the maximum of two numbers not exceeding 21. Thus, a method such as

public int blackjack(int a, int b); 

However, if someone wanted to return all the winning hands (assuming that the location in the input array was a place at the table), so the signature, for example:

 /** * returns an array indicate the index in the specified hands that * correspond to the winning locations. Will return an empty array if * there are no winners. The length of the returned array is how many * winning hands there were * @param hands The total for each hand, where the index is the seat * @return the index/"seat" where a winning hand was found; may return * an empty array */ public int[] blackjack(int[] hands) { ... } 

Thus, based on input data such as (only using 3 "players" in the "seats" 0, 1, 2):

{17, 15, 23}
{23, 25, 22}
{18, 16, 18}
{16, 21, 20}

I would expect output line by line:

Hands: [17, 15, 23] winners in [0]
Hands: [23, 25, 22] has no winners
Hands: [18, 16, 18] won the winners in [0, 2]
Hands: [16, 21, 20] have winners in [1]

In past times, I would repeat the hands[] array, find the maximum that was <= 21, and then again search again for each index that was equal to the maximum. So something like this:

 public static int[] blackjackByIteration(int[] hands) { int max = 0; int numAtMax = 0; for (int i = 0; i < hands.length; ++i) { if (hands[i] <= 21 && hands[i] > max) { max = hands[i]; numAtMax = 1; } else if (hands[i] == max) { ++numAtMax; } } int[] winningSeats = new int[numAtMax]; int loc = 0; for (int i = 0; i < hands.length; ++i) { if (hands[i] == max) { winningSeats[loc++] = i; } } return winningSeats; } 

However, I was wondering if there was a more efficient way to implement it through streams. I acknowledge that using Lambdas is not the solution to all problems . I believe that if I read it correctly, it is impossible to immediately find the index of the array int[] , so the approach should be based on the use of List<Integer> , as suggested in the question mentioned above .

I made the initial decision using Streams, but wondered if there was a more efficient approach. I fully acknowledge that my understanding of flows is limited.

 public static int[] blackjackByStreams(int[] hands) { // set to an empty array; no winners in this hand int[] winningSeats = new int[0]; // get the maximum that is <= 21 OptionalInt oi = Arrays.stream(hands).filter(tot -> tot <= 21).max(); // if there are any hands that are <= 21 if (oi.isPresent()) { // have to make a list (?) List<Integer> list = Arrays.stream(hands) .boxed() .collect(Collectors.toList()); // find the location(s) in the list winningSeats = IntStream.range(0, list.size()) .filter(i -> list.get(i) == oi.getAsInt()) .toArray(); } return winningSeats; } 

Two approaches return the same data, so this is not about functionality. Rather, is there a way to make blackjackByStreams better? Moreover, is there a way to eliminate the creation of a List<Integer> list ?

Edit: I read this question here in which one answer suggested creating a custom collector. Not sure if this will be the only alternative approach.

Thank you for the information provided.

+6
source share
1 answer

You are missing a simple solution if you find the maximum element. Just create a Stream over the array indices directly, instead of an intermediate list:

 public static int[] blackjackByIteration(int[] hands) { OptionalInt oi = Arrays.stream(hands).filter(i -> i <= 21).max(); if (oi.isPresent()) { int value = oi.getAsInt(); return IntStream.range(0, hands.length).filter(i -> hands[i] == value).toArray(); } return new int[0]; } 
+4
source

All Articles