我正在使用一個 CSV 檔案,其中包含一些有關事故的資訊。
我創建了Accident型別:
private Integer driverAge;
private Integer vehicleAge;
public Accident(Integer driverAge, Integer vehicleAge) {
this.driverAge = driverAge;
this.vehicleAge = vehicleAge;
}
我還創建了一個讀取所有 CSV 檔案的函式,將所有事故轉換為 aList<Accident>并將其保存為這種型別AccidentArchive:
private List<Accident> accidents;
public AccidentArchive(List<Accident> accidents) {
this.accidents = accidents;
}
所以,我們正在使用我還不完全理解的流,??我一直堅持這個練習,我必須創建一個回傳 a 的函式,SortedMap<K, V>其中鍵必須是driverAge值,值必須是按具有相同值的最低值的降序排序的串列:nvehicleAge driverAge
public SortedMap<Integer, List<Integer>> getNMinVehicleAgesPerDriverAge(Integer n) {
return getAccidents().stream().
...
我嘗試過使用Collectors.toMap()并Collectors.toList()以某種方式使其作業,但我不知道該怎么做。
uj5u.com熱心網友回復:
簡化方法
這個問題與N通過部分排序找到最大值(或最小值)的演算法問題相關。使用收集器的實作可能看起來很困難,因此我決定引入一個簡化的解決方案。
我們可以使用一個groupingBy()需要三個引數的風格:
- 一個
classifier函式, - 供應商
mapFactory(允許指定生成的地圖型別) - 和一個下游收集器。
作為下游收集器,groupingBy()我們可以使用收集器和函式collectingAndThen的組合,該函式將對映射到每個鍵的整個結果串列進行排序,然后洗掉不必要的值,僅保留最低:mapping()toList()nvehicleAge
public SortedMap<Integer, List<Integer>> getNMinVehicleAgesPerDriverAge(Integer n) {
return getAccidents().stream()
.collect(Collectors.groupingBy(Accident::getDriverAge,
TreeMap::new,
Collectors.collectingAndThen(
Collectors.mapping(Accident::getVehicleAge, Collectors.toList()),
list -> list.stream()
.sorted(Comparator.reverseOrder())
.limit(n)
.collect(Collectors.toList()))));
}
性能更高的版本
正如我之前所說,當我們只需要其中一些值時,我們不需要對映射到每個鍵的所有值進行排序。當n與串列的總大小(例如每個鍵)相比3時100,000,它會導致嚴重的性能損失。
我們可以通過 using 引入部分排序PriorityQueue(這是 JDK 內置的 Heap 資料結構的一種實作)。
為了增強以前的解決方案,我們需要替換下游收集器,groupingBy()您可以使用組合mapping()和由它們支持的自定義收集器PriorityQueue,它們只保留與每個相關聯的n最低vehicleAge值driverAge:
public SortedMap<Integer, List<Integer>> getNMinVehicleAgesPerDriverAge(Integer n) {
return getAccidents().stream()
.collect(Collectors.groupingBy(Accident::getDriverAge,
TreeMap::new,
Collectors.mapping(Accident::getVehicleAge,
getMaxN(n, Comparator.<Integer>reverseOrder()))));
}
下面提供的方法負責根據提供的結果串列和比較器的最大大小生成自定義收集器。此答案中詳細解釋了其背后的邏輯:
public static <T> Collector<T, ?, List<T>> getMaxN(int size, Comparator<T> comparator) {
return Collector.of(
() -> new PriorityQueue<>(comparator),
(Queue<T> queue, T next) -> tryAdd(queue, next, comparator, size),
(Queue<T> left, Queue<T> right) -> {
right.forEach(next -> tryAdd(left, next, comparator, size));
return left;
},
(Queue<T> queue) -> queue.stream().toList(),
Collector.Characteristics.UNORDERED);
}
public static <T> void tryAdd(Queue<T> queue, T next, Comparator<T> comparator, int size) {
if (queue.size() == size && comparator.compare(next, queue.element()) < 0) queue.remove(); // if next value is less than the smallest element in the queue and max size has been exceeded the largest element needs to be removed from the queue
if (queue.size() < size) queue.add(next);
}
順便說一句,如果您的作業沒有指定SortedMap用作回傳型別的要求。最好使用NavigableMap介面,它定義了更廣泛的方法。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/479543.html
上一篇:如何一次呼叫串列中的所有專案?
