Sorting an arraylist of object, and adding values if the name is matching

Viewed 85

I want to sort an arraylist of objects and if the state is the same, then add the value of motorThefts. I am not great at working with array lists, comparing etc so any help is appreciated. -Display each state (in alphabetical order) with the total number of car thefts. Example output:

States and car theft

AK 1898

AL 9599

AR 5377

AZ 48322

I have a class StartUp.java with ArrayList of CityCrime type

    public static ArrayList<CityCrime> crimes = new ArrayList<CityCrime>();

    /**
 * Reads the crime data for each city from file
 */
public static void readCrimeData() {
    
    File file = new File("crimeUSA.csv");

    FileReader fileReader;
    BufferedReader bufferedReader;
    String crimeInfo;
    String[] stats;

    try {
        fileReader = new FileReader(file);
        bufferedReader = new BufferedReader(fileReader);

        crimeInfo = bufferedReader.readLine();
        crimeInfo = bufferedReader.readLine();

        do {
            CityCrime crime = new CityCrime(); // Default constructor
            stats = crimeInfo.split(",");
            {
                if(stats[0] != null) {
                crime.setCity(stats[0]);
            }
            if(stats[1] != null) {
                crime.setState(stats[1]);
            }
            if(stats[2] != null) {
                if(Integer.parseInt(stats[2]) >=0) {
                    crime.setPopulation(Integer.parseInt(stats[2]));
                }
            }
            if(stats[3] != null) {
                if(Integer.parseInt(stats[3]) >=0) {
                    crime.setMurder(Integer.parseInt(stats[3]));
                }
            }
            
            if(stats[4] != null) {
                if(Integer.parseInt(stats[4]) >=0) {
                    crime.setRobbery(Integer.parseInt(stats[4]));
                }
            }
            
            if(stats[5] != null) {
                if(Integer.parseInt(stats[5]) >=0) {
                    crime.setAssault(Integer.parseInt(stats[5]));
                }
            }
                
            if(stats[6] != null) {
                if(Integer.parseInt(stats[6]) >=0) {
                    crime.setBurglary(Integer.parseInt(stats[6]));
                }
            }
            
            if(stats[7] != null) {
                if(Integer.parseInt(stats[7]) >=0) {
                    crime.setLarceny(Integer.parseInt(stats[7]));
                }
            }
            
            if(stats[8] != null) {
                if(Integer.parseInt(stats[8]) >=0) {
                    crime.setMotorTheft(Integer.parseInt(stats[8]));
                }
            }
            
        }
            crimes.add(crime);
            System.out.println(crime);

            crimeInfo = bufferedReader.readLine();

        } while (crimeInfo != null);

        fileReader.close();
        bufferedReader.close();

    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (NumberFormatException e) {
        e.printStackTrace();
    } catch (Exception e) {
        e.printStackTrace();
    }
    
}

These are methods I have so far.

    public static void carThefts() {
    Collections.sort(crimes, new Comparator<CityCrime>(){
        public int compare(CityCrime d1, CityCrime d2){
            return Integer.compare(d1.getMotorTheft(), d2.getMotorTheft());
        }
        
    });
}

public static void displayStateCarThefts() {
    int carTheft = 0;
    for(CityCrime crime : crimes) {
        if(crime.getState().equalsIgnoreCase(crime.getState())) {
            carTheft = carTheft + crime.getMotorTheft();
        }
        
        System.out.printf("%-20s %5s %10s\n", "State", ":" , crime.getState());
        System.out.printf("%-20s %5s %10d\n", "Motor Theft", ":" , carTheft);
    }

    

In my CityCrime.java I have

    public class CityCrime {


//Instance variables

private String city;
private String state;
private int population;
private int murder;
private int robbery;
private int assault;
private int burglary;
private int larceny;
private int motorTheft;
public int totalCrimes;


public static void main(String[] args) {
    
}

public int getTotalCrimes() {
    return totalCrimes;
}

public int setTotalCrimes(int murder, int robbery, int assault, int burglary, int larceny, int motorTheft) {
    this.totalCrimes = murder + robbery + assault + burglary + larceny + motorTheft;
    return totalCrimes;
}

public String getCity() {
    return city;
}


public void setCity(String city) {
    this.city = city;
}

public String getState() {
    return state;
}


public void setState(String state) {
    if(state.equalsIgnoreCase("ALABAMA")) {
        this.state = "AL";
    }
    else if(state.equalsIgnoreCase("ALASKA")) {
        this.state = "AK";
    }

    //etc

public int getMurder() {
    return murder;
}


public void setMurder(int murder) {
    this.murder = murder;
}


public int getRobbery() {
    return robbery;
}


public void setRobbery(int robbery) {
    this.robbery = robbery;

}


public int getAssault() {
    return assault;
}


public void setAssault(int assault) {
    this.assault = assault;

}


public int getBurglary() {
    return burglary;
}


public void setBurglary(int burglary) {
    this.burglary = burglary;

}


public int getLarceny() {
    return larceny;
}


public void setLarceny(int larceny) {
    this.larceny = larceny;
}


public int getMotorTheft() {
    return motorTheft;
}


public void setMotorTheft(int motorTheft) {
    this.motorTheft = motorTheft;

}

public static void showAllMurderDetails() {

    for (CityCrime crime : StartApp.crimes) {
        System.out.println("Crime: City= " + crime.getCity() + ", Murder= " + crime.getMurder());
    }
    System.out.println();
}


public static int showAllViolentCrimes() {
    int total = 0;
    for(CityCrime crime : StartApp.crimes) {
        total=total+crime.getMurder();
        total=total+crime.getRobbery();
        total=total+crime.getAssault();
    }
    System.out.println("Total of violent crimes: " + total);
    return total;
    
}

public static int getPossessionCrimes() {
    int total=0;
    for (CityCrime crime : StartApp.crimes) {
        total = total + crime.getBurglary();
        total = total + crime.getLarceny();
        total = total + crime.getMotorTheft();
    }
    System.out.println("Total of possession crimes: " + total);
    return total;
}

}

I have also went down this route but find myself stuck still :

        public static void displayStateCarThefts() {
    Map<String, CityCrime> map = new HashMap<>();
    for(CityCrime c : crimes) {
        
        CityCrime crime = map.get(c.getState());
        if(crime != null) {
            crime.setMotorTheft(crime.getMotorTheft()+c.getMotorTheft());
        }
        else {
            map.put(c.getState(), c);
        }
    }
    System.out.println(map.values());
    //System.out.println(Arrays.asList(map.values().toArray()));    

}

Really appreciate any help with this. Thankyou

1 Answers

Here my solution:

public static void displayStateCarThefts() {
        final var map = new HashMap<String, Integer>();
        for(var c : crimes) {
            final int previousValue = map.getOrDefault(c.getState(), 0); // If the key does not exist, return 0 as default value
            map.put(c.getState(), previousValue + c.getMotorTheft()); // Update the value on the Map
        }

        final var sortedKeys = new LinkedList<>(map.keySet()); // Create a new list of String with all keys inside
        sortedKeys.sort(Comparator.naturalOrder()); // Sort keys in natural order
        for(final var key: sortedKeys) // Iterate over keys
            System.out.println(key + " " + map.get(key));

}

I see you use ArrayList, I recommand you to use instead LinkedList. ArrayList is an implementation of List using Java array. It is really good to access to a specific element (nth element) but this type of list is not optimal otherwise. Indeed, the implementation have to create new array internally if you want to add an element and if this internal array is full.
LinkedList use the the principle of chained list. Each object inside is wrap in a Node, and Node is connected to previous and next Node forming the list. This type of List is not really efficient to access to nth element, but there is no extra cost to add an element (by add function).
From an iteration perspective, both are, I think, similar in performance.

Why not sort directly the Map?

Because Map is an orderless type. So if there is no order, we can't sort the map.
Don't hesitate if you have any other questions about the code!

Related