开发者社区> 问答> 正文

最有效的方式来遍历CSV并为另一列中的每个唯一值求和一列的值

我有一个CSV文件,其中包含500,000行数据和22列。此数据代表了一年中美国的所有商业航班。我的任务是查找飞行数据集中飞行距离最长的飞机的机尾号。第5列包含每次飞行的飞行员的机尾编号。列22包含行进的总距离。

请extractQ3在下面查看我的方法。首先,HashMap使用createHashMap()方法为整个CSV 创建一个。然后,我运行一个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;
        }
}

问题来源:Stack Overflow

展开
收起
montos 2020-03-25 18:48:15 570 0
1 条回答
写回答
取消 提交回答
  • 答案取决于您所说的“最高效”,“极其低效”和“永恒”。这些是主观术语。答案还可能取决于特定的技术因素(速度与内存消耗;与整体记录数相比的唯一飞行键数;等等)。

    首先,我建议对代码进行一些基本的精简。看看是否可以获得更好(可接受)的结果。如果您需要更多,则可以考虑更高级的改进。

    无论您做什么,都要花一些时间来了解所做任何更改的广泛影响。

    专注于从“可怕”变为“可接受”-然后担心之后需要进行更高级的调整(如果您仍然需要)。

    考虑使用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以找到最大里程:

    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;
        }
    }
    

    警告 -此方法仅供参考。它只会捕获一个尾号。可能有多架飞机具有相同的最大行驶里程。您将不得不调整自己的逻辑以吸引多个“赢家”。

    通过上述方法,您无需再使用几个现有数据结构以及相关处理。

    如果仍然遇到问题,请放置一些计时器以查看代码中哪些特定区域最慢-然后您将可以集中精力处理更多特定的调整机会。

    回答来源:Stack Overflow

    2020-03-25 18:52:22
    赞同 展开评论 打赏
问答分类:
问答地址:
问答排行榜
最热
最新

相关电子书

更多
低代码开发师(初级)实战教程 立即下载
冬季实战营第三期:MySQL数据库进阶实战 立即下载
阿里巴巴DevOps 最佳实践手册 立即下载