J'ai une simple classe client comme si
public class Customer {
public int age;
public int discount;
public String name;
public Customer(String name) {
this.name = name;
}
public Customer(String name, int age) {
this.name = name;
this.age = age;
}
public Customer(String name, int age, int discount) {
this.name = name;
this.age = age;
this.discount = discount;
}
@Override
public String toString() {
return "Customer [age=" + age + ", discount=" + discount + ", name=" + name + "]";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Integer getDiscount() {
return discount;
}
public void setDiscount(int discount) {
this.discount = discount;
}
}
Je remplir une liste de ces objets en utilisant cette
List<Customer> customerList = new ArrayList<>(Arrays.asList(
new Customer("John", 2, 15),
new Customer("John", 4, 15),
new Customer("John", 6, 25),
new Customer("Joe", 3, 15),
new Customer("Joe", 3, 15),
new Customer("Joe", 3, 15),
new Customer("Goerge", 6, 25),
new Customer("Goerge", 6, 25),
new Customer("Mary", 7, 25),
new Customer("Jane", 1, 15),
new Customer("Jane", 2, 15),
new Customer("Jane", 8, 25),
new Customer("Jane", 8, 25)
));
Maintenant, je veux groupe et compte les noms et les remises, en utilisant un collecteur comme celui-ci
Map<Object, Long> collected = customerList
.stream()
.collect(Collectors.groupingBy(x -> Arrays.asList(x.name, x.discount), Collectors.counting()));
Je peux revoir ma sortie en utilisant cette
collected.entrySet().forEach(c -> {
System.out.println(c);
});
Ce qui produit les éléments suivants
[Jane, 15]=2
[Joe, 15]=3
[John, 15]=2
[Mary, 25]=1
[John, 25]=1
[Jane, 25]=2
[Goerge, 25]=2
La question est de savoir comment puis-je trier la carte par son nom et de réduction de sorte qu'il ressemble à ceci
[Goerge, 25]=2
[Jane, 15]=2
[Jane, 25]=2
[Joe, 15]=3
[John, 15]=2
[John, 25]=1
[Mary, 25]=1
Je continue à se cogner contre le type d'objet qui est retourné par le collecteur?
Puis-je jetai le collecteur afin qu'il retourne une classe, peut-être quelque chose comme
private class DiscountCounts
{
public String name;
public Integer discount;
}
Est - il possible de convertir Map<**Object**, Long>()
à quelque chose comme Map<DiscountCounts, Long>()
, ce serait permettre l' accès aux champs de la clé Carte en utilisant lambda ou des constructions Comparator?
J'ai essayé quelque chose comme ça, itérer sur la carte et convertir manuellement à la carte Je veux, mais je ne peux pas obtenir aux clés de la collection originale?
Map<DiscountCounts, Long> collected2 = new HashMap<>();
collected.entrySet().forEach(o -> {
DiscountCounts key1 = (DiscountCounts)o.getKey(); //--> Fails here
collected2.put((DiscountCounts)o.getKey(), o.getValue());
});
Une façon vous pouvez le faire sans utiliser la DiscountCounts
classe est, d' abord trier la liste, puis effectuer la tâtonnement par le fonctionnement et l' utilisation LinkedHashMap
pour enregistrer l'ordre de tri
Map<List<Object>, Long> map = customerList.stream()
.sorted(Comparator.comparing(Customer::getName).thenComparing(Customer::getDiscount))
.collect(Collectors.groupingBy(x -> Arrays.asList(x.name, x.discount),LinkedHashMap::new, Collectors.counting()));
L'autre façon en utilisant la DiscountCounts
classe est, par dérogation à la equals
et hashcode
de la DiscountCounts
classe et faire une création groupingBy DiscountCounts
objet pour chaque Customer
objet comme clé Map
et l' utilisation TreeMap
avec Comparator
pour trier le résultat
Map<DiscountCounts, Long> result = customerList.stream().collect(Collectors.groupingBy(
c -> new DiscountCounts(c.getName(), c.getDiscount()),
() -> new TreeMap<DiscountCounts, Long>(
Comparator.comparing(DiscountCounts::getName).thenComparing(DiscountCounts::getDiscount)),
Collectors.counting()));
@Andreas Suggest dans le commentaire Enlighten - moi une autre façon de le faire, et je pense que c'est l' un des meilleurs approche que vous pouvez mettre en œuvre Comparable
sur DiscountCounts
et fournir la logique de tri de sorte que vous n'avez pas besoin de fournir à ComparatorTreeMap
@Override
public int compareTo(DiscountCounts cust) {
int last = this.getName().compareTo(cust.getName());
return last == 0 ? this.getDiscount().compareTo(cust.getDiscount()) : last;
}
Map<DiscountCounts, Long> result1 = customerList.stream().collect(Collectors.groupingBy(
c -> new DiscountCounts(c.getName(), c.getDiscount()), TreeMap::new, Collectors.counting()));