我有一个像这样的简单客户类
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;
}
}
我使用此填充这些对象的列表
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)
));
现在我想使用这样的收集器对名称和折扣进行分组和计数
Map<Object, Long> collected = customerList
.stream()
.collect(Collectors.groupingBy(x -> Arrays.asList(x.name, x.discount), Collectors.counting()));
我可以使用这个查看我的输出
collected.entrySet().forEach(c -> {
System.out.println(c);
});
输出以下内容
[Jane, 15]=2
[Joe, 15]=3
[John, 15]=2
[Mary, 25]=1
[John, 25]=1
[Jane, 25]=2
[Goerge, 25]=2
问题是如何按名称和折扣对 map 进行排序,使其看起来像这样
[Goerge, 25]=2
[Jane, 15]=2
[Jane, 25]=2
[Joe, 15]=3
[John, 15]=2
[John, 25]=1
[Mary, 25]=1
我不断遇到收集器返回的对象类型?
我可以转换收集器以便它返回一个类,也许是类似的东西
private class DiscountCounts
{
public String name;
public Integer discount;
}
是否可以转换 Map<**Object**, Long>()
类似 Map<DiscountCounts, Long>()
,这是否允许使用 lambda 或 Comparator 构造访问 Map 键的字段?
我尝试了类似的方法,迭代 map 并手动转换为我想要的 map ,但我无法获取原始集合的键?
Map<DiscountCounts, Long> collected2 = new HashMap<>();
collected.entrySet().forEach(o -> {
DiscountCounts key1 = (DiscountCounts)o.getKey(); //--> Fails here
collected2.put((DiscountCounts)o.getKey(), o.getValue());
});
最佳答案
不使用 DiscountCounts 类的一种方法是,首先对列表进行排序,然后按操作进行摸索,并使用 LinkedHashMap 保存排序顺序
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()));
使用 DiscountCounts
类的另一种方法是,重写 DiscountCounts
类的 equals
和 hashcode
并执行分组通过为每个 Customer
对象创建 DiscountCounts
对象作为 Map
中的键,并将 TreeMap
与 Comparator< 结合使用
对结果进行排序
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 在评论中建议启发我另一种方法,我认为这是您可以在 DiscountCounts
上实现 Comparable
并提供的最佳方法之一排序逻辑,这样您就不需要向 TreeMap
提供 Comparator
@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()));
关于Java 8 Sort HashMap,其中映射键是 <String, Integer> 的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60733383/