我想构建一个Map,其中包含按其值排序的元素。我收到包含{customerId,PurchaseAmount}的购买清单,并希望构建一个表格映射,将客户映射到他们的总购买金额。单个客户可能有多次购买。
最后,我想按客户逐个处理此信息,以减少总购买金额。意味着我先处理支出最高的客户,然后处理支出最低的客户。
为此,我最初的解决方案是构建一个Map(使用HashMap),将此Map转换为一个List(LinkedList),以降序对这个List进行排序,然后处理这个List。这是一个O(n log n)解决方案,我相信这是最好的时间复杂度。但是,我想知道是否有某种方法可以利用诸如TreeMap之类的数据结构,该结构具有其固有的排序属性。默认情况下,它将按其键排序,但是我想按值对其进行排序。我目前的解决方案如下。
public class MessageProcessor {
public static void main(String[] args) {
List<Purchase> purchases = new ArrayList<>();
purchases.add(new Purchase(1, 10));
purchases.add(new Purchase(2, 20));
purchases.add(new Purchase(3, 10));
purchases.add(new Purchase(1, 22));
purchases.add(new Purchase(2, 100));
processPurchases(purchases);
}
private static void processPurchases(List<Purchase> purchases) {
Map<Integer, Double> map = new HashMap<>();
for(Purchase p: purchases) {
if(!map.containsKey(p.customerId)) {
map.put(p.customerId, p.purchaseAmt);
}else {
double value = map.get(p.customerId);
map.put(p.customerId, value + p.purchaseAmt);
}
}
List<Purchase> list = new LinkedList<>();
for(Map.Entry<Integer, Double> entry : map.entrySet()) {
list.add(new Purchase(entry.getKey(), entry.getValue()));
}
System.out.println(list);
Comparator<Purchase> comparator = Comparator.comparing(p -> p.getPurchaseAmt());
list.sort(comparator.reversed());
//Process list
//...
}
class Purchase {
int customerId;
double purchaseAmt;
public Purchase(int customerId, double purchaseAmt) {
this.customerId = customerId;
this.purchaseAmt = purchaseAmt;
}
public double getPurchaseAmt() {
return this.purchaseAmt;
}
}
当前代码完成了我想做的事情,但是我想知道是否有一种方法可以避免将Map转换为List,然后使用自定义Comparator对List进行排序。也许使用某种排序的Map。任何意见,将不胜感激。另外,对于如何使我的代码更具可读性或习惯性的建议,我们将不胜感激。谢谢。这是我关于StackOverflow的第一篇文章
答案 0 :(得分:1)
首先TreeMap
对您不起作用,因为它是按键而不是按值排序的。另一种选择是LinkedHashMap
。按插入顺序排序。
您还可以使用Java Streams处理列表:
Map<Integer, Double> map = purchases.stream()
.collect(Collectors.toMap(Purchase::getCustomerId, Purchase::getPurchaseAmt, (a, b) -> a + b));
这将创建一个地图,其中以customerId
为键,并包含所有购买的总金额。接下来,您可以通过使用另一个流并将其迁移到LinkedHashMap
进行排序:
LinkedHashMap<Integer, Double> sorted = map.entrySet().stream()
.sorted(Comparator.comparing(Map.Entry<Integer, Double>::getValue).reversed())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> {
throw new IllegalStateException("");
}, LinkedHashMap::new));
最后,如果需要,您可以再次创建一个新列表:
List<Purchase> list = sorted.entrySet().stream()
.map(e -> new Purchase(e.getKey(), e.getValue()))
.collect(Collectors.toList());
如果您想获得有关Java Streams的更多基本信息,here是官方教程。