我有一个包含看起来像这样的数据的列表
game_id | user_id | status
1 1 STARTED
2 1 FINISHED
1 2 STARTED
2 2 FINISHED
我想将此列表收集到两张地图中(或尽可能在一张地图中)
一张地图应该将user_id
映射到用户玩过的游戏数量-基本上是具有finished
状态的游戏
user_id | finished_games
1 1
2 1
另一张地图应将user_id
存储到所有游戏计数中。看起来像这样
user_id | all_games
1 2
2 2
我这样做(我删除了game_id
字段,因为实际上并不重要)
import java.util.*;
import java.util.stream.*;
public class MyClass {
public static void main(String args[]) {
List<Game> games = Arrays.asList(
create("user-1", "STARTED"),
create("user-2", "STARTED"),
create("user-1", "FINISHED"),
create("user-2", "FINISHED"),
create("user-1", "FINISHED"),
create("user-2", "FINISHED")
);
// expect user-1: all_games (3), finished_games (2)
Map<String, Long> allGames = games
.stream()
.collect(Collectors.groupingBy(Game::getUserId, Collectors.counting()));
System.out.println(allGames);
Map<String, Long> finishedGames = games
.stream()
.filter(game -> game.battleStatus.equals("FINISHED"))
.collect(Collectors.groupingBy(Game::getUserId, Collectors.counting()));
System.out.println(finishedGames);
}
private static Game create(String id, String status) {
Game game = new Game();
game.userId = id;
game.battleStatus = status;
return game;
}
private static class Game {
String userId;
String battleStatus;
public String getUserId() {
return userId;
}
}
}
似乎工作正常。但是,当我计算具有状态的游戏时,会进行过滤以仅保留具有FINISHED
状态的项目。
Map<String, Long> finishedGames = games
.stream()
.filter(game -> game.battleStatus.equals("FINISHED"))
.collect(Collectors.groupingBy(Game::getUserId, Collectors.counting()));
是否有一种方法可以在collect
块中实现而不是使用filter
?
答案 0 :(得分:3)
您可以使用多个groupingBy
来获取此信息,例如:
Map<String, Map<String, Long>> gameStatuses = games
.stream()
.collect(Collectors.groupingBy(Game::getUserId,
Collectors.groupingBy(Game::getBattleStatus, Collectors.counting())));
System.out.println(gameStatuses);
为此,您需要为Game
的{{1}}类添加一个吸气剂,例如:
battleStatus
这将为您提供以下输出:
private static class Game {
String userId;
String battleStatus;
public String getUserId() {
return userId;
}
public String getBattleStatus() {
return battleStatus;
}
}
您可以使用嵌套的{user-1={STARTED=1, FINISHED=2}, user-2={STARTED=1, FINISHED=2}}
获取任何用户和任何状态的计数。
答案 1 :(得分:1)
如果您需要同时计算完成和未完成的游戏,那么另外一个groupingBy
可以为您提供帮助:
Function<Game, Boolean> isFinished = game -> "FINISHED".equals(game.battleStatus);
Map<String, Map<Boolean, Long>> groupedGames =
games.stream()
.collect(groupingBy(Game::getUserId,
groupingBy(isFinished, counting())));
或者您可能想按battleStatus
本身进行分组:
Map<String, Map<String, Long>> groupedGames =
games.stream()
.collect(groupingBy(Game::getUserId,
groupingBy(game -> game.battleStatus, counting())));
我什至会创建一个吸气剂getBattleStatus()
,然后将game -> game.battleStatus
替换为方法引用Game::getBattleStatus
:
Map<String, Map<String, Long>> groupedGames =
games.stream()
.collect(groupingBy(Game::getUserId,
groupingBy(Game::getBattleStatus, counting())));