Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is a good java data structure for storing nested items (like cities in states)?

I'm just getting started in Java and am looking for advice on a good way to store nested sets of data. For example, I'm interested in storing city population data that can be accessed by looking up the city in a given state. (Note: eventually, other data will be stored with each city as well, this is just the first attempt at getting started.)

The current approach I'm using is to have a StateList Object which contains a HashMap that stores State Objects via a string key (i.e. HashMap<String, State>). Each State Object contains its own HashMap of City Objects keyed off the city name (i.e. HashMap<String, City>).

A cut down version of what I've come up with looks like this:

// TestPopulation.java

public class TestPopulation {

  public static void main(String [] args) {

    // build the stateList Object
    StateList sl = new StateList();

    // get a test state
    State stateAl = sl.getState("AL");

    // make sure it's there.
    if(stateAl != null) {

      // add a city
      stateAl.addCity("Abbeville");

      // now grab the city
      City cityAbbevilleAl = stateAl.getCity("Abbeville");

      cityAbbevilleAl.setPopulation(2987);

      System.out.print("The city has a pop of: ");
      System.out.println(Integer.toString(cityAbbevilleAl.getPopulation()));

    }

    // otherwise, print an error
    else {
      System.out.println("That was an invalid state");
    } 
  }
}

// StateList.java

import java.util.*;

public class StateList {

  // define hash map to hold the states
  private HashMap<String, State> theStates = new HashMap<String, State>();

  // setup constructor that loads the states
  public StateList() {

    String[] stateCodes = {"AL","AK","AZ","AR","CA","CO"}; // etc...

    for (String s : stateCodes) {
      State newState = new State(s);
      theStates.put(s, newState);
    }
  }

  // define method for getting a state
  public State getState(String stateCode) {
    if(theStates.containsKey(stateCode)) {
      return theStates.get(stateCode);
    }
    else {
      return null;
    } 
  }
}

// State.java

import java.util.*;

public class State {

  // Setup the state code
  String stateCode;

  // HashMap for cities
  HashMap<String, City> cities = new HashMap<String, City>();

  // define the constructor
  public State(String newStateCode) {
    System.out.println("Creating State: " + newStateCode);
    stateCode = newStateCode;
  }

  // define the method for adding a city
  public void addCity(String newCityName) {
    City newCityObj = new City(newCityName);
    cities.put(newCityName, newCityObj); 
  }

  // define the method for getting a city
  public City getCity(String cityName) {
    if(cities.containsKey(cityName)) {
      return cities.get(cityName);
    }
    else {
      return null;
    } 
  }
}

// City.java

public class City {

  // Define the instance vars
  String cityName;
  int cityPop;

  // setup the constructor
  public City(String newCityName) {
    cityName = newCityName;
    System.out.println("Created City: " + newCityName);
  }

  public void setPopulation(int newPop) {
    cityPop = newPop;
  }

  public int getPopulation() {
    return cityPop;
  }
}

This is working for me, but I'm wondering if there are gotchas that I haven't run into, or if there are alternate/better ways to do the same thing.

(P.S. I know that I need to add some more error checking in, but right now, I'm focused on trying to figure out a good data structure.)

(NOTE: Edited to change setPop() and getPop() to setPopulation() and getPopulation() respectively to avoid confucsion)

like image 694
Alan W. Smith Avatar asked Dec 05 '25 19:12

Alan W. Smith


2 Answers

If you really need these kinds of aggregation (StaleList that have States, States that have Cities), then this is the correct way to implement. It may not be the most straightforward, but it is the most object oriented approach. So, for the cost of minimalism, you sure get cohesion, coupling, maintainability and all those fancy software engineering adjectives. For small projects, these characteristics should not be enforced. But for big software projects they make sense and avoid really bad code (but do not guarantee really good code).

You can also use some third-party libraries (like the one from Pangea answer) to help keeping the code simple.

See:

1: http://en.wikipedia.org/wiki/Cohesion_(computer_science)

2: http://en.wikipedia.org/wiki/Coupling_(computer_science)

3: http://en.wikipedia.org/wiki/Maintainability

like image 198
fjsj Avatar answered Dec 08 '25 11:12

fjsj


Checkout the Multimap data structure from guava collections. This is not the complete answer to your solution but will simplify to certain level. But the beauty is that now you can use MapMaker to cache your "population queries" against the city.

Multimap<String, City> stateToCities = ArrayListMultimap.create();

stateToCities.put("GA",new City("Atlanta",100000));
stateToCities.put("GA",new City("Cumming",50000));
like image 22
Aravind Yarram Avatar answered Dec 08 '25 11:12

Aravind Yarram



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!