Est-il possible d'utiliser Collectors.groupingBy()
avec Collectors.counting()
pour compter dans le champ d'un objet personnalisé au lieu de créer une carte et de la transformer ensuite.
J'ai une liste d'utilisateurs, comme ceci:
public class User {
private String firstName;
private String lastName;
// some more attributes
// getters and setters
}
Je veux compter tous les utilisateurs avec le même prénom et le même nom. Par conséquent, j'ai un objet personnalisé ressemblant à ceci:
public static class NameGroup {
private String firstName;
private String lastName;
private long count;
// getters and setters
}
Je peux collecter les groupes de noms en utilisant ceci:
List<NameGroup> names = users.stream()
.collect(Collectors.groupingBy(p -> Arrays.asList(p.getFirstName(), p.getLastName()), Collectors.counting()))
.entrySet().stream()
.map(e -> new NameGroup(e.getKey().get(0), e.getKey().get(1), e.getValue()))
.collect(Collectors.toList());
Avec cette solution, je dois d'abord regrouper les utilisateurs sur une carte et la transformer ensuite en mon objet personnalisé. Est-il possible de compter tous les noms directement dans nameGroup.count
pour éviter d'itérer deux fois sur la liste (ou la carte) et améliorer les performances?
Je ne sais pas quelles sont vos exigences mais j'ai modifié votre classe NameGroup pour accepter une classe User au lieu de prénom et nom. Cela a ensuite éliminé la nécessité de sélectionner les valeurs dans le flux intermédiaire de List et uniquement dans un flux d'Utilisateur. Mais cela nécessite toujours la carte.
List<NameGroup> names =
users.stream().collect(Collectors.groupingBy(p -> p,Collectors.counting()))
.entrySet().stream()
.map(e -> new NameGroup(e.getKey(), e.getValue())).collect(
Collectors.toList());
public static class NameGroup {
// ...
@Override
public boolean equals(Object other) {
final NameGroup o = (NameGroup) other;
return firstName.equals(o.firstName) && lastName.equals(o.lastName);
}
@Override
public int hashCode() {
return Objects.hash(firstName, lastName);
}
@Override
public String toString() {
return firstName + " " + lastName + " " + count;
}
}
public static void main(String[] args) throws IOException {
List<User> users = new ArrayList<>();
users.add(new User("fooz", "bar"));
users.add(new User("fooz", "bar"));
users.add(new User("foo", "bar"));
users.add(new User("foo", "bar"));
users.add(new User("foo", "barz"));
users.stream()
.map(u -> new NameGroup(u.getFirstName(), u.getLastName(), 1L))
.reduce(new HashMap<NameGroup, NameGroup>(), (HashMap<NameGroup, NameGroup> acc, NameGroup e) -> {
acc.compute(e, (k, v) -> v == null ? e : new NameGroup(e.firstName, e.lastName, e.count + acc.get(e).count));
return acc;
}, (a, b) -> {
b.keySet().forEach(e -> a.compute(e, (k, v) -> v == null ? e : new NameGroup(e.firstName, e.lastName, e.count + a.get(e).count)));
return a;
}).values().forEach(x -> System.out.println(x));
}
Cela produira
fooz bar 2
foo barz 1
foo bar 2