[英]Java: Most efficient way to loop through CSV and sum values of one column for each unique value in another Column
我有一個包含 500,000 行數據和 22 列的 CSV 文件。 該數據代表了美國一年內的所有商業航班。 我的任務是找到數據集中飛行里程最多的飛機的尾號。 第 5 列包含每個航班的飛機尾號。 第 22 列包含行駛的總距離。
請參閱下面我的extractQ3
方法。 首先,使用createHashMap()
方法為整個 CSV 創建一個HashMap
。 然后,我運行了一個for
循環來識別數據集中每個唯一的尾號,並將它們存儲在一個名為tailNumbers
的數組中。 然后對於每個唯一的尾號,我遍歷整個Hashmap
以計算該尾號的總距離。
代碼在較小的數據集上運行良好,但一旦大小增加到 500,000 行,代碼就會變得非常低效,並且需要永遠運行。 誰能為我提供更快的方法來做到這一點?
public class FlightData {
HashMap<String,String[]> dataMap;
public static void main(String[] args) {
FlightData map1 = new FlightData();
map1.dataMap = map1.createHashMap();
String answer = map1.extractQ3(map1);
}
public String extractQ3(FlightData map1) {
ArrayList<String> tailNumbers = new ArrayList<String>();
ArrayList<Integer> tailMiles = new ArrayList<Integer>();
//Filling the Array with all tail numbers
for (String[] value : map1.dataMap.values()) {
if(Arrays.asList(tailNumbers).contains(value[4])) {
} else {
tailNumbers.add(value[4]);
}
}
for (int i = 0; i < tailNumbers.size(); i++) {
String tempName = tailNumbers.get(i);
int miles = 0;
for (String[] value : map1.dataMap.values()) {
if(value[4].contentEquals(tempName) && value[19].contentEquals("0")) {
miles = miles + Integer.parseInt(value[21]);
}
}
tailMiles.add(miles);
}
Integer maxVal = Collections.max(tailMiles);
Integer maxIdx = tailMiles.indexOf(maxVal);
String maxPlane = tailNumbers.get(maxIdx);
return maxPlane;
}
public HashMap<String,String[]> createHashMap() {
File flightFile = new File("flights_small.csv");
HashMap<String,String[]> flightsMap = new HashMap<String,String[]>();
try {
Scanner s = new Scanner(flightFile);
while (s.hasNextLine()) {
String info = s.nextLine();
String [] piecesOfInfo = info.split(",");
String flightKey = piecesOfInfo[4] + "_" + piecesOfInfo[2] + "_" + piecesOfInfo[11]; //Setting the Key
String[] values = Arrays.copyOfRange(piecesOfInfo, 0, piecesOfInfo.length);
flightsMap.put(flightKey, values);
}
s.close();
}
catch (FileNotFoundException e)
{
System.out.println("Cannot open: " + flightFile);
}
return flightsMap;
}
}
答案取決於您所說的“最有效”、“效率極低”和“需要永恆”是什么意思。 這些是主觀術語。 答案也可能取決於特定的技術因素(速度與內存消耗;唯一飛行鍵的數量與總記錄數量相比;等等)。
我建議首先對您的代碼應用一些基本的精簡。 看看這是否能讓您獲得更好的(可接受的)結果。 如果您需要更多,那么您可以考慮更高級的改進。
無論您做什么,都要花一些時間來了解您所做的任何更改的廣泛影響。
專注於從“糟糕”到“可接受”——然后再擔心更高級的調整(如果你仍然需要它)。
考慮使用BufferedReader
而不是Scanner
。 見這里。 盡管掃描儀可能剛好滿足您的需求(即,如果它不是瓶頸)。
考慮在掃描儀循環中使用邏輯來在一次數據傳遞中捕獲尾數和累積里程。 為了清楚和簡單起見,以下是故意基本的:
// The string is a tail number.
// The integer holds the accumulated miles flown for that tail number:
Map<String, Integer> planeMileages = new HashMap();
if (planeMileages.containsKey(tailNumber)) {
// add miles to existing total:
int accumulatedMileage = planeMileages.get(tailNumber) + flightMileage;
planeMileages.put(tailNumber, accumulatedMileage);
} else {
// capture new tail number:
planeMileages.put(tailNumber, flightMileage);
}
之后,一旦您完成了掃描儀循環,您就可以遍歷您的planeMileages
里程planeMileages
以找到最大的里程數:
String maxMilesTailNumber;
int maxMiles = 0;
for (Map.Entry<String, Integer> entry : planeMileages.entrySet()) {
int planeMiles = entry.getValue();
if (planeMiles > maxMiles) {
maxMilesTailNumber = entry.getKey();
maxMiles = planeMiles;
}
}
警告- 這種方法僅用於說明。 它只會捕獲一個尾數。 可能有多架飛機具有相同的最大里程。 您必須調整邏輯以捕獲多個“贏家”。
上述方法消除了對現有數據結構和相關處理的需要。
如果您仍然遇到問題,請放置一些計時器以查看代碼的哪些特定區域最慢 - 然后您將有更多可以關注的特定調整機會。
我建議您使用 java 8 Stream API,以便您可以利用並行流。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.