ジャワ:CSVと別の列に一意の各値に対して1つの列の合計値をループするための最も効率的な方法

FinDev:

私は、データ500,000行と22列を含むCSVファイルを持っています。このデータは、一年間のアメリカの商業フライトを表します。私は、データセットの中で最もマイルを飛んだ飛行機の尾数を見つけることを任務としているのです。第5列には、各フライトのairplainの尾の番号が含まれています。コラム22は、総移動距離が含まれています。

私の参照してくださいextractQ3以下の方法を。まず、作成しHashMap使用して全体のCSVのためのcreateHashMap()方法を。その後、私は走ったforデータセット内のすべてのユニークな尾の番号を識別するためのループをしてと呼ばれる配列にそれらを保存しますtailNumbersそして、それぞれのユニークな尾数のために、私は、全体を通じてループしHashmapている尾数に対する距離の合計マイルを計算します。

コードは小さなデータセットで罰金を実行しますが、サイズの50万行のコードに上昇した後は、恐ろしく非効率的になり、実行に永遠になります。誰もがこれを行うにはより高速な方法を私に提供することができますか?

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

答えは、あなたが「最も効率的」によって何を意味するかに依存して「恐ろしく非効率的」と「永遠を取ります」。これらは、主観的な用語です。答えはまた、特定の技術的要因(;全体のレコード数に比べてユニークな飛行キーの数、などのメモリ消費速度対)に依存してもよいです。

私は開始するには、あなたのコードにいくつかの基本的な合理化を適用することをお勧めします。それはあなたがより良い(許容)の結果を取得する場合参照してください。あなたがより多く必要な場合は、より高度な改善点を検討することができます。

何をするにしても、あなたが行った変更の幅広い影響を理解するために、いくつかのタイミングを取ります。

その後、その後、より高度なチューニングについての心配(あなたはまだそれを必要とする場合) - 「許容される」と「恐ろしい」から行くに焦点を当てています。

使用を検討してBufferedReader代わりにScanner参照してくださいここに(それがボトルネックではない場合すなわち)スキャナは、あなたのニーズに合わせてちょうど良いかもしれないが。

データの1回のパスでのテール番号や累積走行距離をキャプチャするために、あなたのスキャナループ内のロジックを使用することを検討してください。以下は、明瞭かつ簡潔にするために、意図的に基本的なものです:

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

警告 -このアプローチは、単に例示のためのものです。それは唯一の尾の番号をキャプチャします。同じ最大の走行距離を持つ複数の面がある可能性があります。あなたは、複数の「勝者」をキャプチャするためにあなたのロジックを調整する必要があります。

上記のアプローチは、既存のデータ構造のいくつかの、および関連処理の必要性を取り除きます。

もし、まだ顔の問題であれば、あなたのコードの領域が最も遅いである特定見るためにいくつかのタイマーに入れて - そして、あなたはあなたが集中することができ、より具体的なチューニングの機会を持つことになります。

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=284202&siteId=1