2016-04-25 12 views
6

Sulla base di uno BlackJack Question, mi sono chiesto come indicare tutte le mani vincenti. La domanda iniziale semplicemente chiesto, in effetti, circa il massimo di due numeri non maggiori di 21. Quindi, un metodo comeC'è un approccio Java 8 Stream più efficiente per trovare l'indice in un [] int?

public int blackjack(int a, int b); 

Tuttavia, se uno volesse restituire tutti delle mani vincenti (assumendo la posizione nella array di input era un posto ad un tavolo), quindi una firma come:

/** 
* 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) { ... } 

quindi in base ai dati di input come (usando solo 3 "giocatori" a "sedi" 0, 1, 2):

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

ci si aspetterebbe di uscita lungo le linee di:

mani: [17, 15, 23] ha vincitori [0]
mani: [23, 25, 22] non ha vincitori
mani: [18, 16, 18] ha vincitori [0, 2]
mani: [16, 21, 20] ha vinto a [1]

In passato, avrei ripetuto l'array hands[], trovato il massimo che era < = 21 e poi ripetuto di nuovo l'individuazione di ciascun indice uguale al massimo. Quindi qualcosa del genere:

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; 
} 

Tuttavia, mi chiedevo se esistesse un modo più efficiente di implementarlo tramite i flussi. Sono consapevole che using Lambdas is not the solution to all problems. Credo che, se ho letto correttamente, non è possibile trovare direttamente l'indice di un array int[], quindi l'approccio deve fare affidamento sull'uso di un List<Integer>, come suggerito nello question referenced above.

Ho fatto una soluzione iniziale utilizzando Streams, ma mi chiedevo se esistesse un approccio più efficiente. Ammetto pienamente che la mia comprensione dei flussi è limitata.

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; 
} 

I due approcci restituiscono gli stessi dati, quindi non è una questione di funzionalità per sé. Piuttosto, c'è un modo per rendere il blackjackByStreams migliore? Soprattutto, c'è un modo per eliminare la creazione del List<Integer> list?

Modifica: ho letto this question here, in cui una risposta suggeriva la creazione di un raccoglitore personalizzato. Non sono sicuro se questo sarebbe l'unico approccio alternativo.

Grazie per aver fornito informazioni.

+0

Gli stream non migliorano, in generale, l'efficienza. Gli stream non saranno generalmente più veloci e spesso più lenti dello stesso programma scritto normalmente. Sono solo una biblioteca, non sono magici. Il tuo codice iniziale sarà almeno altrettanto veloce e probabilmente più veloce. –

risposta

4

Ti manca la soluzione semplice quando hai trovato l'elemento massimo.Basta creare uno stream sugli indici della matrice direttamente invece di avere una lista intermedia:

+0

Pensavo di averlo provato e ho ricevuto un errore, ma nel pensarci probabilmente ho provato ad usare "Arrays.stream (hands) ..." piuttosto che "IntStream.range (0, hands.length) ...". Grande miglioramento nella concisione del metodo! – KevinO

+1

@Holger Non necessariamente, la matrice potrebbe avere tutti i valori superiori a 21, quindi OptionInt sarebbe vuoto. È sfortunato che non ci sia 'mapToObj' su' OptionalInt', altrimenti potremmo avere 'oi.mapToObj (...). OElseGet (() -> new int [0])' – Tunaki

+1

In effetti, questo è un problema. Dovrei avere un altro caffè ... Cosa si potrebbe fare per evitare che 'if' sia' int value = oi.orElse (21); 'e procedere con il secondo stream op, che produrrà un array vuoto quando non ci sono corrispondenze. Penso ancora, ci dovrebbe essere qualcosa di più facile ... – Holger

Problemi correlati