我几乎完成了大学的扑克项目,但是我仍然在Java流方面苦苦挣扎。 我编写了一个HandEvaluator类,该类计算每个玩家手牌的强度并将其分配给玩家。现在,我尝试将具有最高手分数的一个或多个玩家(如果一个以上的玩家具有相同的得分/平分底池)添加到列表中,以计算出胜负。
我对流的语法有疑问。我正在尝试这样的事情:
playerList.stream().max(Comparator.comparing(Player::getHandScore)).get();
这将返回得分最高的播放器,但是如果有多个得分相同的玩家怎么办?以及如何将它们添加到列表中?
答案 0 :(得分:3)
我做了这样的事情。我按分数分组,然后找到具有最大键值的分数。它将返回Optional
中的Map.Entry
。它既包含最大值,又包含拥有它的玩家。然后,我可以使用getValue()
方法获得球员名单。
List<Player> value = playerList.stream()
.collect(groupingBy(Player::getScore))
.entrySet()
.stream()
.max(Comparator.comparing(Map.Entry::getKey))
.get()
.getValue();
答案 1 :(得分:2)
一种易于理解的解决方案如下:
int maxHighScore = playerList.stream()
.map(player -> player.getHandScore())
.max()
.orElse(-1);
List<Player> highestHandScores = playerList.stream()
.filter(player -> player.getHandScore() == maxHighScore)
.collect(Collectors.toList());
第一步,我们获得maxHighScore,第二步,我们过滤玩家以仅保留得分最高的玩家。
答案 2 :(得分:1)
int max = playerList.stream()
.max(Comparator.comparing(Player::getHandScore))
.get()
.getHandScore();
List<Player> playerLists = playerList
.stream()
.filter(m -> m.getHandScore() == max)
.collect(Collectors.toList());
答案 3 :(得分:1)
我对其他一些答案的问题是,他们两次遍历球员名单-一次用于按球员得分分组,另一次用来获取得分最高的球员。在正常情况下,这可能微不足道,但是当玩家人数较多时,可能会成为问题。
为了避免两次遍历列表,要做的一件事是使用SortedMap
。一旦我们按照玩家的得分将他们分组,我们可以简单地调用lastKey()
一次获得最高的键:
SortedMap<Integer, List<Player>> topPlayers = playerList.stream()
.collect(Collectors.groupingBy(Player::getScore, TreeMap::new, Collectors.toList()));
topPlayers.get(topPlayers.lastKey());
或者,正如Holger在评论中所说,如果您使用NavigableMap
,则可以保存另一个地图查找:
NavigableMap<Integer, List<Player>> topPlayers = playerList.stream()
.collect(Collectors.groupingBy(Player::getScore, TreeMap::new, Collectors.toList()));
topPlayers.lastEntry().getValue();
但是,在我看来,链接文章的answer given by Stuart Marks更好,因为并非所有元素都已存储(分组到存储桶中),但是,如果发现它们不属于所有元素,则会立即将其删除达到最大程度。
这可能节省内存。
答案 4 :(得分:1)
我的答案将是带有SortedMap
的{{3}}版本,但是此版本将在找到得分较高的单个Player时立即丢弃“较低”的组。此版本适用于确实存在很多元素的情况,其中保留所有可见元素可能会成为问题。例如,当从非常大的文件中读取流式项目时,该项目就无法放入内存中。
整个解决方案如下:
List<Player> topScore = playersStream().collect(
topGroup(Comparator.comparingInt(Player::getHandScore))
);
要使其正常工作,您将需要一个带有状态容器的自定义收集器来保留组。我不确定JDK中是否有类似的东西(无论如何都不是8),但是您可能可以在其中的一个库中找到它。面向外的方法如下:
static <T> Collector<T, ?, List<T>> topGroup(final Comparator<? super T> comparator) {
Objects.requireNonNull(comparator, "comparator");
return Collector.of(
() -> new Group<>(comparator),
// My local compiler can't infer type properly, I had to help it.
// Your experience may be different
(BiConsumer<Group<T>, T>) Group::accept,
Group::merge,
Group::asList
);
}
最重要的部分是有状态的Group<T>
。目的是作为外部比较器认为顺序最高的元素的容器。一旦遇到较高顺序的元素,该组就会丢弃其所有先前的内容。示例实现为:
private static class Group<T> {
private final Comparator<? super T> comparator;
T sample;
List<T> more;
public Group(Comparator<? super T> comparator) {
this.comparator = comparator;
}
public void accept(T el) {
if (sample == null) {
sample = el;
}
else {
int order = comparator.compare(sample, el);
if (order == 0) {
more().add(el);
}
else if (order > 0) {
// element of a higher order, discard everything and make it a sample
sample = el;
more = null;
}
// else {element of a lower order, ignore}
}
}
public Group<T> merge(Group<T> other) {
if (this.comparator != other.comparator) {
throw new IllegalArgumentException("Cannot merge groups with different orders");
}
if (sample == null) {
return other; // we're empty
}
int order = comparator.compare(this.sample, other.sample);
if (order >= 0) {
if (order == 0) {
// merge with other group
more().addAll(other.asList());
}
return this;
}
else {
// other group is higher than us
return other;
}
}
public List<T> asList() {
List<T> result = new ArrayList<>();
if (sample != null) {
result.add(sample);
}
if (more != null) {
result.addAll(more);
}
return result;
}
}
此实现也是解决找到“与关系排名靠前的N个问题”(其中我的实现为“与关系排名靠前的1个问题”)的门户。