Tengo la lista que contiene los datos que tiene este aspecto
game_id | user_id | status
1 1 STARTED
2 1 FINISHED
1 2 STARTED
2 2 FINISHED
Quiero recoger esta lista en dos mapas (o en un solo mapa si es posible)
Un mapa debe mantener el mapeo de user_id
que el número de los juegos que jugó usuario - básicamente juegos con finished
estados
user_id | finished_games
1 1
2 1
Otro mapa debe almacenar user_id
para contar todos los juegos. Se vería como esto
user_id | all_games
1 2
2 2
Lo hago así (me quita game_id
el campo como lo es que no es importante, de hecho)
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;
}
}
}
Parece que funciona bien. Pero cuando calculo juegos con el estado, filtro de I con el fin de dejar sólo los elementos con FINISHED
el estado.
Map<String, Long> finishedGames = games
.stream()
.filter(game -> game.battleStatus.equals("FINISHED"))
.collect(Collectors.groupingBy(Game::getUserId, Collectors.counting()));
¿Hay una manera de lograr que en el interior collect
del bloque en lugar de utilizar filter
?
Si necesita contar con ambos juegos acabados y sin acabar, y luego otro groupingBy
le puede ayudar a:
Function<Game, Boolean> isFinished = game -> "FINISHED".equals(game.battleStatus);
Map<String, Map<Boolean, Long>> groupedGames =
games.stream()
.collect(groupingBy(Game::getUserId,
groupingBy(isFinished, counting())));
O puede que quiera agrupar por battleStatus
sí mismo:
Map<String, Map<String, Long>> groupedGames =
games.stream()
.collect(groupingBy(Game::getUserId,
groupingBy(game -> game.battleStatus, counting())));
Yo incluso crear un captador getBattleStatus()
y luego vuelva a colocar game -> game.battleStatus
con referencia método Game::getBattleStatus
:
Map<String, Map<String, Long>> groupedGames =
games.stream()
.collect(groupingBy(Game::getUserId,
groupingBy(Game::getBattleStatus, counting())));