开发者

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();
开发者_JAVA百科
    // 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)


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


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


I would consider using one class to manage a list States containing member variables of City and population in two-dimensional arrays.

Other thoughts: cityAbbevilleAl is not checked against null. At first, I misread getPop as a pop method and not population.


Spell out "population". Key strokes are cheap. You've already confused one responser here; it's likely that others won't get it at first, either.

Can population be negative? If not, I'd check that in your contract for setPopulation().

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜