Le titre est génial, mais Collectors.groupingBy est juste une histoire formidable.
Récemment, il y a eu de nombreux cas de création de diverses cartes en utilisant groupingBy (pour une raison quelconque, il y a eu peu de cas de création de cartes, donc je ne les ai pas beaucoup utilisées). Cet article est un résumé de ce qui a été étudié à ce moment-là.
Java10 Lombok
L'avantage de Collectors.groupingBy est que vous pouvez facilement les agréger en leur donnant une clé. Si vous souhaitez modifier la valeur de Map, vous pouvez ajouter un autre argument et l'écrire ici, afin qu'il prenne en charge l'agrégation dans divers cas.
List<Integer> nums = List.of(1,2,3,4,5,6,7,8,9,1,1,1);
Map<Integer,List<Integer>> map = nums.stream().collect(Collectors.groupingBy(i ->i));
System.out.println(map);
=> {1=[1, 1, 1, 1], 2=[2], 3=[3], 4=[4], 5=[5], 6=[6], 7=[7], 8=[8], 9=[9]}
Cependant, la plus grande caractéristique de groupingBy est qu'il fonctionne bien même si vous définissez des clés compliquées. La définition de plusieurs clés est très facile, il suffit de passer plusieurs champs lors de la spécification des clés. "-" Est ajouté pour faciliter la visualisation, mais il n'y a pas de problème.
En tant que clé cette fois, nom1 et nom2 seront définis comme clés.
public static void main(String[] arg) {
List<String> names = List.of("taro", "jiro", "saburo");
List<Name> nameList = names.stream().map(it -> new Name(it, it, it)).collect(Collectors.toList());
Map<String,List<Name>> map = nameList.stream()
.collect(Collectors.groupingBy(it -> it.getName1() + "-" + it.getName2()));
System.out.println(map);
// => {jiro-jiro=[Main.Name(name1=jiro, name2=jiro, name3=jiro)], saburo-saburo=[Main.Name(name1=saburo, name2=saburo, name3=saburo)], taro-taro=[Main.Name(name1=taro, name2=taro, name3=taro)]}
}
@Data
private static class Name {
private String name1;
private String name2;
private String name3;
public Name(String name1, String name2, String name3) {
this.name1 = name1;
this.name2 = name2;
this.name3 = name3;
}
}
Avec cela seul, nom3 a la même valeur, vous ne pouvez donc pas dire si nom1 et nom2 sont les clés.
Je voudrais donc ajouter nouveau nom (" taro "," jiro "," taro ")
à la liste et voir quel type de carte peut être créé.
public static void main(String[] arg) {
List<String> names = List.of("taro", "jiro", "saburo");
List<Name> nameList = names.stream().map(it -> new Name(it, it, it)).collect(Collectors.toList());
nameList.add(new Name("taro", "jiro", "taro"));
Map<String,List<Name>> map = nameList.stream()
.collect(Collectors.groupingBy(it -> it.getName1() + "-" + it.getName2()));
System.out.println(map);
// => {jiro-jiro=[Main.Name(name1=jiro, name2=jiro, name3=jiro)], saburo-saburo=[Main.Name(name1=saburo, name2=saburo, name3=saburo)], taro-taro=[Main.Name(name1=taro, name2=taro, name3=taro)], taro-jiro=[Main.Name(name1=taro, name2=jiro, name3=taro)]}
}
Comme vous pouvez le voir dans le résultat, l'objet ajouté cette fois est indépendant car taro-jiro = [Main.Name (name1 = taro, name2 = jiro, name3 = taro)]
, donc name1 et name2 sont Vous pouvez voir que c'était la clé.
Ce qui est inquiétant ici, c'est que le nom résultant3 contient "taro". L'avantage de groupingBy est qu'il fait la même chose pour les valeurs de champs autres que ceux spécifiés dans la clé, même si elles sont identiques aux autres champs.
Je voudrais courir avec name1 et name3 comme clés pour vérifier si c'est vrai.
public static void main(String[] arg) {
List<String> names = List.of("taro", "jiro", "saburo");
List<Name> nameList = names.stream().map(it -> new Name(it, it, it)).collect(Collectors.toList());
nameList.add(new Name("taro", "jiro", "taro"));
Map<String,List<Name>> map = nameList.stream()
.collect(Collectors.groupingBy(it -> it.getName1() + "-" + it.getName3()));
System.out.println(map);
// => {jiro-jiro=[Main.Name(name1=jiro, name2=jiro, name3=jiro)], saburo-saburo=[Main.Name(name1=saburo, name2=saburo, name3=saburo)], taro-taro=[Main.Name(name1=taro, name2=taro, name3=taro), Main.Name(name1=taro, name2=jiro, name3=taro)]}
}
Lorsque vous vérifiez le résultat de l'exécution, l'objet ajouté comme nouveau nom (" taro "," jiro "," taro ") ʻis
taro-taro = [Main.Name (nom1 = taro, nom2 = taro, nom3 = taro) ), Main.Name (name1 = taro, name2 = jiro, name3 = taro)] ʻet est enregistré comme la valeur de la clé de taro-taro
comme prévu.
Regardons un autre modèle d'exemples name1 et name3. Vous pouvez voir les champs jusqu'à l'exemple précédent, mais regardons également l'exemple où nom1 et nom3 sont échangés.
public static void main(String[] arg) {
List<String> names = List.of("taro", "jiro", "saburo");
List<Name> nameList = names.stream().map(it -> new Name(it, it, it)).collect(Collectors.toList());
nameList.add(new Name("taro", "jiro", "taro"));
nameList.add(new Name("jiro", "taro", "taro"));
Map<String,List<Name>> map = nameList.stream()
.collect(Collectors.groupingBy(it -> it.getName1() + "-" + it.getName3()));
System.out.println(map);
// => {jiro-jiro=[Main.Name(name1=jiro, name2=jiro, name3=jiro)], saburo-saburo=[Main.Name(name1=saburo, name2=saburo, name3=saburo)], jiro-taro=[Main.Name(name1=jiro, name2=taro, name3=taro)], taro-taro=[Main.Name(name1=taro, name2=taro, name3=taro), Main.Name(name1=taro, name2=jiro, name3=taro)]}
}
Il semble que même si vous modifiez l'ordre, il répondra correctement.
J'ai essayé l'exemple précédent avec le type Integer.
public static void main(String[] arg) {
List<Integer> nums = List.of(1,2,3);
List<Name> nameList = nums.stream().map(it -> new Name(it, it, it)).collect(Collectors.toList());
nameList.add(new Name(1, 2, 1));
nameList.add(new Name(2, 1, 1));
Map<Integer,List<Name>> map = nameList.stream()
.collect(Collectors.groupingBy(it -> it.getName1() + it.getName2()));
System.out.println(map);
}
@Data
private static class Name {
private Integer name1;
private Integer name2;
private Integer name3;
public Name(Integer name1, Integer name2, Integer name3) {
this.name1 = name1;
this.name2 = name2;
this.name3 = name3;
}
}
Dans ce cas, il semble être agrégé par le résultat du calcul de la clé. Ce serait étrange s'il y avait plusieurs clés avec la même clé, donc je suis convaincu.
Il semble qu'il soit agrégé par le résultat du calcul, mais juste au cas où, vérifiez si vous pouvez le voir sur le terrain.
public static void main(String[] arg) {
List<Integer> nums = List.of(1,2,3);
List<Name> nameList = nums.stream().map(it -> new Name(it, it, it)).collect(Collectors.toList());
nameList.add(new Name(1, 1, 2));
nameList.add(new Name(1, 2, 1));
Map<Integer,List<Name>> map = nameList.stream()
.collect(Collectors.groupingBy(it -> it.getName1() + it.getName3()));
System.out.println(map);
// => 2=[Main.Name(name1=1, name2=1, name3=1), Main.Name(name1=1, name2=2, name3=1)], 3=[Main.Name(name1=1, name2=1, name3=2)], 4=[Main.Name(name1=2, name2=2, name3=2)], 6=[Main.Name(name1=3, name2=3, name3=3)]}
}
@Data
private static class Name {
private Integer name1;
private Integer name2;
private Integer name3;
public Name(Integer name1, Integer name2, Integer name3) {
this.name1 = name1;
this.name2 = name2;
this.name3 = name3;
}
}
Il l'a également vu en type Integer.
Il s'agit du troisième essai de type Integer. Supposons maintenant que vous convertissiez la clé en chaîne et que vous l'utilisiez comme clé.
public static void main(String[] arg) {
List<Integer> nums = List.of(1,2,3);
List<Name> nameList = nums.stream().map(it -> new Name(it, it, it)).collect(Collectors.toList());
nameList.add(new Name(1, 2, 1));
nameList.add(new Name(2, 1, 1));
Map<String,List<Name>> map = nameList.stream()
.collect(Collectors.groupingBy(it -> it.getName1() + "-" + it.getName2()));
System.out.println(map);
// => {1-1=[Main.Name(name1=1, name2=1, name3=1)], 2-1=[Main.Name(name1=2, name2=1, name3=1)], 1-2=[Main.Name(name1=1, name2=2, name3=1)], 2-2=[Main.Name(name1=2, name2=2, name3=2)], 3-3=[Main.Name(name1=3, name2=3, name3=3)]}
}
@Data
private static class Name {
private Integer name1;
private Integer name2;
private Integer name3;
public Name(Integer name1, Integer name2, Integer name3) {
this.name1 = name1;
this.name2 = name2;
this.name3 = name3;
}
}
Dans ce cas, la commande semble être prise en considération.
Vérifions s'il n'y a pas de problème même si on augmente le nombre de clés.
public static void main(String[] arg) {
List<String> names = List.of("taro", "jiro", "saburo");
List<Name> nameList = names.stream().map(it -> new Name(it, it, it)).collect(Collectors.toList());
nameList.add(new Name("taro","taro","jiro"));
nameList.add(new Name("taro","jiro","taro"));
Map<String,List<Name>> map = nameList.stream()
.collect(Collectors.groupingBy(it -> it.getName1() + "-" + it.getName2() + "-" + it.getName3()));
System.out.println(map);
// => {jiro-jiro-jiro=[Main.Name(name1=jiro, name2=jiro, name3=jiro)], taro-jiro-taro=[Main.Name(name1=taro, name2=jiro, name3=taro)], taro-taro-taro=[Main.Name(name1=taro, name2=taro, name3=taro)], taro-taro-jiro=[Main.Name(name1=taro, name2=taro, name3=jiro)], saburo-saburo-saburo=[Main.Name(name1=saburo, name2=saburo, name3=saburo)]}
}
@Data
private static class Name {
private String name1;
private String name2;
private String name3;
public Name(String name1, String name2, String name3) {
this.name1 = name1;
this.name2 = name2;
this.name3 = name3;
}
}
Il semble que vous pouvez augmenter le nombre de clés.
J'ai pensé essayer un peu plus, mais maintenant que j'ai saisi la tendance, je terminerai en résumant le fonctionnement de goingupingBy.
Fondamentalement, il semble que ce soit une méthode qui crée le champ spécifié dans la clé selon l'expression Lambda et l'agrège par cette valeur. S'il s'agit d'un type String, vous pouvez voir que l'ordre spécifié et le champ sont liés et que la clé l'est, et s'il s'agit d'un type numérique, vous pouvez voir si le résultat créé est le même car le résultat du calcul du champ spécifié est la clé. Je vais.
Il s'avère que goupingBy est vraiment puissant. Cela peut être encore plus fort lorsqu'il est combiné avec d'autres méthodes dans Collectors, mais j'aimerais saisir une autre opportunité (je ne sais pas s'il y a une opportunité).
Au fait, je n'ai pas examiné le traitement interne de Java dans cet article, donc je ne sais pas pourquoi cela se produit!
Recommended Posts