Подсчет объектов с одинаковым значением свойства

Я создаю покер решатель ранга, и я должен считать карты с той же масти или того же ранга в наборе карт. Здесь я создаю HashMap и значение приращения, если в наборе несколько рангов.

private boolean isFourOfAKind() {
        Map<RANK, Integer> rankDuplicates = new HashMap<>();
        for(Card card : cards) {
            rankDuplicates.put(card.getRank(), rankDuplicates.getOrDefault(card.getRank(), 0) + 1);
        }
        return rankDuplicates.containsValue(4);
    }

мне было интересно, возможно ли использовать потоки делать то же самое с потоками java. Это выглядело бы примерно так:--4-->

    private boolean isFourOfAKind() {
        Map<RANK, Integer> rankDuplicates = cards.stream()
            .map(Card::getRank)
            .collect(Collectors.toMap(/*...something goes here..*/)); // of course this is very wrong, but you can see what I'm aiming at.
        return rankDuplicates.containsValue(4);
    }

2 ответов


похоже, вы ищете что-то вроде

return cards.stream()
        .collect(Collectors.toMap(Card::getRank, e -> 1, Integer::sum))
        //                        keyMapper, valueMapper, mergeFunction
        .containsValue(4);

другой вариант с groupingBy:

import static java.util.stream.Collectors.counting;
import static java.util.stream.Collectors.groupingBy;

...

private boolean isFourOfAKind() {
    return cards.stream()
                .collect(groupingBy(Card::getRank, counting()))
                .containsValue(4L);

}

в основном вы группируете карту по рангам, так что у вас есть Map<Rank, List<Card>>

затем вы используете нижний коллектор counting() сопоставить каждый список с его количеством элементов, чтобы конечный результат был Map<Rank, Long> (вы также можете использовать summingInt(i -> 1) вместо counting() Если вам действительно нужно иметь Map<Rank, Integer>).