1

I'm new to Java 8 lambdas and streams. For practice, i'm trying to "translate" some methods from a school project into lambdas/streams when possible. Here it's the old method.

As you can see, i need to give to discard method a int, which is the number of the first playable card into the hand of the player.

public Card autoPlay(Card flipped) {
    for (int i = 0; i < super.getHand().size(); i++) {
        if (super.getHand().get(i).isCompatible(flipped)) { //check if card from hand is compatible with flipped card (same number or color)
            return (this.discard(i)); //remove from hand and returns it
        }
    }
    return null; //if any compatible card found
}

So far, the new version of my method is:

public Card newAutoPlay(Card flipped){
   return super.getHand().stream().filter(card -> card.isCompatible(flipped)).findFirst().get();

}

I found out how to get the first compatible card, but not how to get it's index... I read about IntStreams (and using the size of the list as a range), but i don't understand how to use it in this particular case.

Is it possible to achieve what i'm trying to do, or it's not a good idea to do this?

EDIT: After exploring the question, using streams in this case brings too much complexity and not enough readability for solving this simple problem. So i've choose to a for loop. Also some other changes, but the core idea remains the same. Thanks all for helping.

@Override
public String play(Uno unoGame) {
    int i = 0;
    boolean found = false;

    for (i = 0; i < super.getHand().size() && !found; i++) {
        found = super.getHand().get(i).isCompatible(unoGame.getFlippedCard());
    }

    return found ? "play " + i : "draw";
}

2 Answers2

3

I would suggest the following solution to your existing code using Java 8 lambdas which requires to change the signature of discard(int index) to discard(Card card), assuming Card does implement equals(Object obj) and hashCode():

public Card autoPlay(Card flipped) {
    Optional<Card> card = getHand().stream()
            .filter(flipped::isCompatible)
            .findFirst();
    card.ifPresent(this::discard);
    return card.orElse(null);
}

private void discard(Card card) {
    // your code removing the first matching card from your hand
}

Instead of returning null you may consider changing the signature of Card autoPlay(Card flipped) to Optional<Card> autoPlay(Card flipped).

Harmlezz
  • 7,972
  • 27
  • 35
2

one liner:

   IntStream.range(0,getHand()::size).filter(i -> super.getHand().get(i).isCompatible(flipped))
                .mapToObj(Integer::new).findFirst().map(this::discard).orElse(null);

It's necessary to mapToObj because the map function on an Optional of type int doesn't exist. Sadly, java lacks native support for pairs which would make this less ugly. It could them "stream with index". Keep something in mind though: Streams are meant to be infinite and thus have no index.

Christian Bongiorno
  • 5,150
  • 3
  • 38
  • 76