Java: наиболее эффективный способ l oop через CSV и суммирования значений одного столбца для каждого уникального значения в другом столбце - PullRequest
0 голосов
/ 15 марта 2020

У меня есть CSV-файл с 500 000 строк данных и 22 столбцами. Эти данные представляют все коммерческие рейсы в США за один год. Мне поручено найти номер хвоста самолета, который пролетел больше всего миль в наборе данных. Колонка 5 содержит номер хвоста самолета для каждого полета. Столбец 22 содержит общее пройденное расстояние.

Пожалуйста, см. Мой метод extractQ3 ниже. Сначала создали HashMap для всего CSV, используя метод createHashMap(). Затем я запустил for l oop для идентификации каждого уникального номера хвоста в наборе данных и сохранил их в массиве с именем 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;
        }
}

Ответы [ 2 ]

1 голос
/ 15 марта 2020

Ответ зависит от того, что вы подразумеваете под «наиболее эффективным», «ужасно неэффективным» и «занимает вечность». Это субъективные термины. Ответ также может зависеть от конкретных c технических факторов (скорость и потребление памяти; количество уникальных ключей полета по сравнению с общим количеством записей; et c.).

Я бы порекомендовал применить немного основы c упрощения вашего кода, для начала. Посмотрите, даст ли это вам лучший (приемлемый) результат. Если вам нужно больше, тогда вы можете рассмотреть более продвинутые улучшения.

Что бы вы ни делали, потратьте немного времени, чтобы понять общие последствия любых изменений, которые вы делаете.

Сосредоточьтесь на переходе от «ужасного» к «приемлемому», а затем подумайте о более продвинутой настройке после этого (если она вам все еще нужна).

Попробуйте использовать BufferedReader вместо Scanner. Смотрите здесь . Хотя сканер может подойти для ваших нужд (т. Е. Если он не является узким местом).

Рассмотрите возможность использования logi c в вашем сканере l oop для захвата хвостовых чисел и накопленного пробега за один проход данные. Ниже приведено намеренно основа c, для ясности и простоты:

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

После того, как вы завершили сканер l oop, вы можете выполнить итерацию по вашему 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;
    }
}

ПРЕДУПРЕЖДЕНИЕ - Этот подход только для иллюстрации. Он будет захватывать только один номер хвоста. Может быть несколько самолетов с одинаковым максимальным пробегом. Вам нужно настроить логику c для захвата нескольких «победителей».

Приведенный выше подход устраняет необходимость в нескольких ваших существующих структурах данных и связанной с ними обработке.

Если вы по-прежнему Столкнувшись с проблемами, установите некоторые таймеры, чтобы увидеть, какие конкретно области вашего кода c медленнее - и тогда у вас будет больше возможностей для настройки c, на которые вы можете сфокусироваться.

0 голосов
/ 15 марта 2020

Я предлагаю вам использовать java 8 Stream API, чтобы вы могли использовать преимущества параллельных потоков.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...