简体   繁体   中英

optimising the search time in hashmap

I have a csv file which is hashmapped, whenever the user enter the city name(key) it will display all the details of that city. I have to optimize the search result time, everytime the it is reading the file(instead of only once) and displaying the values. The CSV files contains data like this :

city,city_ascii,lat,lng,country,iso2,iso3,admin_name,capital,population,id Malishevë,Malisheve,42.4822,20.7458,Kosovo,XK,XKS,Malishevë,admin,,1901597212 Prizren,Prizren,42.2139,20.7397,Kosovo,XK,XKS,Prizren,admin,,1901360309 Zubin Potok,Zubin Potok,42.9144,20.6897,Kosovo,XK,XKS,Zubin Potok,admin,,1901608808

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Scanner;
import java.io.IOException;
public class CSVFileReaders{
public static void main(String[] args) {
    String filePath = "C:\\worldcities1.csv";
    Scanner in = new Scanner(System.in);                                      
    System.out.println(" \n Enter the City name to be Searched :   \n _> ");
    long start = System.currentTimeMillis();
    String searchTerm = in.nextLine();
    readAndFindRecordFromCSV(filePath, searchTerm);
    long end = System.currentTimeMillis(); 
    System.out.println(" \n It took " + (end - start) + " Milli Seconds to search the result \n");
    in.close();
}

public static void readAndFindRecordFromCSV( String filePath, String searchTerm) {
    try{            
        HashMap<String,ArrayList<String>> cityMap = new HashMap<String,ArrayList<String>>();        
        Scanner x = new Scanner (new File(filePath),"UTF-8");
        String city= "";
        while(x.hasNextLine()) {
        ArrayList<String> values = new ArrayList<String>();
        String name  = x.nextLine();
        //break each line of the csv file to its elements
        String[] line = name.split(",");
        city = line[1];
            for(int i=0;i<line.length;i++){
                values.add(line[i]);            
            }
        cityMap.put(city,values);       
        }
        x.close();
        //Search the city
        if(cityMap.containsKey(searchTerm)) {

                System.out.println("City name is : "+searchTerm+"\nCity details are accordingly in the order :"
                                    + "\n[city , city_ascii , lat , lng , country , iso2 , iso3 , admin_name , capital , population , id] \n"
                                    +cityMap.get(searchTerm)+"");

            }           
        else {
            System.out.println("Enter the correct City name");
        }                       
    }
    catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

}`

the time should be optimized and every time i search it is reading the entire file(which should happen)

Currently you mix the map initialization inside the search function.
You don't want that.
First, init the map, then use it in the search function.
To do that, extract a method for statements that instantiate and value the map and then refactor the readAndFindRecordFromCSV() method so that it accepts a Map as additional parameter :

 public static void readAndFindRecordFromCSV( String filePath, String searchTerm,  HashMap<String,ArrayList<String>> dataByCity) {...}

With refactoring IDE features, it should be simple enough : "extracting method" then "change signature".

Here is a code (not tested at runtime but tested at compile time) that splits the logical in separated tasks and also rely on instance methods :

public class CSVFileReaders {

    private final String csvFile;
    private HashMap<String, ArrayList<String>> cityMap;
    private final Scanner in = new Scanner(System.in);

    public static void main(String[] args) {
        String filePath = "C:\\worldcities1.csv";
        CSVFileReaders csvFileReaders = new CSVFileReaders(filePath);
        csvFileReaders.createCitiesMap();
        csvFileReaders.processUserFindRequest(); // First search
        csvFileReaders.processUserFindRequest(); // Second search
    }


    public CSVFileReaders(String csvFile) {
        this.csvFile = csvFile;
    }

    public void createCitiesMap() {
        cityMap = new HashMap<>();
        try (Scanner x = new Scanner(new File(csvFile), "UTF-8")) {
            String city = "";
            while (x.hasNextLine()) {
                ArrayList<String> values = new ArrayList<String>();
                String name = x.nextLine();
                //break each line of the csv file to its elements
                String[] line = name.split(",");
                city = line[1];
                for (int i = 0; i < line.length; i++) {
                    values.add(line[i]);
                }
                cityMap.put(city, values);
            }
            x.close();
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }
    }


    public void processUserFindRequest() {

        System.out.println(" \n Enter the City name to be Searched :   \n _> ");
        long start = System.currentTimeMillis();
        String searchTerm = in.nextLine();
        long end = System.currentTimeMillis();
        System.out.println(" \n It took " + (end - start) + " Milli Seconds to search the result \n");
        //Search the city
        if (cityMap.containsKey(searchTerm)) {
            System.out.println("City name is : " + searchTerm + "\nCity details are accordingly in the order :"
                                       + "\n[city , city_ascii , lat , lng , country , iso2 , iso3 , admin_name , capital , population , id] \n"
                                       + cityMap.get(searchTerm) + "");
        } else {
            System.out.println("Enter the correct City name");
        }
    }
}

The interesting part is here :

String filePath = "C:\\worldcities1.csv";
CSVFileReaders csvFileReaders = new CSVFileReaders(filePath);
csvFileReaders.createCitiesMap();
csvFileReaders.processUserFindRequest(); // First search
csvFileReaders.processUserFindRequest(); // Second search

The logical is clearer now.

Why do you create / load the CSV into a HashMap with every search ? Just create the HashMap only once in the beginning , and then on every search just check whether it exists in the HashMap, eg move the read part into a separate method :

HashMap<String,ArrayList<String>> cityMap = new HashMap<String,ArrayList<String>>(); 

public static void readCSVIntoHashMap( String filePath) {
    try{            

        Scanner x = new Scanner (new File(filePath),"UTF-8");
        String city= "";
        while(x.hasNextLine()) {
        ArrayList<String> values = new ArrayList<String>();
        String name  = x.nextLine();
        //break each line of the csv file to its elements
        String[] line = name.split(",");
        city = line[1];
            for(int i=0;i<line.length;i++){
                values.add(line[i]);            
            }
        cityMap.put(city,values);       
        }
        x.close();
    ...
    }

Then have a separate method for searching :

public static void search(String searchTerm) {
  if(cityMap.containsKey(searchTerm)) {
  ...
}
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM