Java:最有效的循环方式,通过CSV和一列的值和另一列中每个唯一值的总和
我有一个CSV文件,包含500000行数据和22列。该数据代表一年内美国所有的商业航班。我的任务是找出数据集中飞行里程数最多的飞机的机尾号。第5列包含每一航班的飞机尾号。第22列包含行驶的总距离 请参阅下面我的Java:最有效的循环方式,通过CSV和一列的值和另一列中每个唯一值的总和,java,arrays,hashmap,Java,Arrays,Hashmap,我有一个CSV文件,包含500000行数据和22列。该数据代表一年内美国所有的商业航班。我的任务是找出数据集中飞行里程数最多的飞机的机尾号。第5列包含每一航班的飞机尾号。第22列包含行驶的总距离 请参阅下面我的extractQ3方法。首先,使用createHashMap()方法为整个CSV创建一个HashMap。然后,我运行了一个for循环来识别数据集中每个唯一的尾号,并将它们存储在一个名为tailNumbers的数组中。然后,对于每个唯一的尾号,我循环遍历整个Hashmap,计算该尾号的总里程
extractQ3
方法。首先,使用createHashMap()
方法为整个CSV创建一个HashMap
。然后,我运行了一个for
循环来识别数据集中每个唯一的尾号,并将它们存储在一个名为tailNumbers
的数组中。然后,对于每个唯一的尾号,我循环遍历整个Hashmap
,计算该尾号的总里程
该代码在较小的数据集上运行良好,但一旦大小增加到500000行,代码就会变得非常低效,需要花费很长时间才能运行。有谁能给我提供一个更快的方法吗
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;
}
}
公共类FlightData{
HashMap数据映射;
公共静态void main(字符串[]args){
FlightData map1=新的FlightData();
map1.dataMap=map1.createHashMap();
字符串answer=map1.extractQ3(map1);
}
公共字符串提取Q3(FlightData映射1){
ArrayList tailNumber=新的ArrayList();
ArrayList tailMiles=新的ArrayList();
//用所有尾数填充数组
对于(字符串[]值:map1.dataMap.values()){
if(Arrays.asList(tailnumber).contains(值[4]){
}否则{
尾号。添加(值[4]);
}
}
对于(int i=0;i
我建议您使用Java8流API,这样您就可以利用并行流 答案取决于你所说的“效率最高”、“效率极低”和“需要一段时间”是什么意思。这些都是主观的术语。答案也可能取决于具体的技术因素(速度与内存消耗;唯一飞行钥匙的数量与总体记录的数量相比;等等)
首先,我建议对代码进行一些基本的简化。看看这是否会给你带来更好(可接受)的结果。如果你需要更多,那么你可以考虑更高级的改进。
无论你做什么,都要花点时间来了解你所做的任何改变的广泛影响。
专注于从“糟糕”到“可接受”——然后再担心之后的更高级的调整(如果您仍然需要的话)
考虑使用BufferedReader
而不是扫描仪
。看见尽管扫描仪可能正好满足您的需要(即,如果不是瓶颈)
考虑使用扫描仪循环中的逻辑来捕获一次数据传递中的尾数和累计里程。为了清晰和简单起见,以下内容是特意设计的基本内容:
// 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);
}
警告-此方法仅用于说明。它将只捕获一个尾号。可能有多架飞机具有相同的最大里程。你将不得不调整你的逻辑来捕捉多个“赢家”
上述方法消除了对一些现有数据结构和相关处理的需要
如果您仍然面临问题,请输入一些计时器,查看代码的哪些特定区域最慢,然后您将有更多具体的调整机会可以关注。非常感谢您的回答,它为我指明了正确的方向,大大加快了代码的速度。然而,我现在得到了错误的答案。你能用你的策略看看我的最新帖子吗?如果你有任何建议,请告诉我
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;
}
}