计算具有相同属性值的对象

Art*_*ūrs 9 java hashmap java-8 java-stream

我正在创建一个扑克排名求解器,我必须在一组牌中计算具有相同套装或同等级别的牌.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);
    }
Run Code Online (Sandbox Code Playgroud)

我想知道是否有可能使用流与java流完全相同的事情.它看起来像这样:

    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);
    }
Run Code Online (Sandbox Code Playgroud)

Psh*_*emo 9

看起来你正在寻找类似的东西

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

  • 对我来说,`.collect(Collectors.groupingBy(Card :: getRank,Collectors.counting())`看起来更干净...... (2认同)

Ale*_* C. 5

另一种变体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);

}
Run Code Online (Sandbox Code Playgroud)

基本上你按照等级对牌进行分组,这样你就有了 Map<Rank, List<Card>>

然后使用下游收集器counting()将每个列表映射到其元素数量,以便最终结果为Map<Rank, Long>(如果您确实需要,也可以使用summingInt(i -> 1)而不是).counting()Map<Rank, Integer>

  • 作为附录,如果`Rank`是一个`enum`,使用`.collect(groupingBy(Card :: getRank,() - > new EnumMap(Rank.class),counting()))`可能稍微有点效率. (4认同)