Question

Here's my data set:

<zoo>
  <animal type="dog" breed="beagle" name="charlie" />
  <animal type="dog" breed="beagle" name="chester" />
  <animal type="dog" breed="retriever" name="goldie" />
  <animal type="duck" breed="mallard" name="lord quackerton" />
</zoo>

I want to transform this data into a big Java object, a hashmap of hashmaps of arrays. Toward that end, I've written the following code:

Map<String, Map<String, ArrayList<String>>> expectedTypes = new HashMap();
Map<String, ArrayList<String>> expectedBreeds = new HashMap();
ArrayList<String> expectedNames = new ArrayList();

// Each <animal> element has already been stored in an array called 'zoo'
for( int i = 0; i < zoo.length; i++) {
    // Grab string values from XML file, using XMLbeans:
    String thisExpectedType = tests[i].getType();
    String thisExpectedBreed = tests[i].getBreed();
    String thisExpectedName = tests[i].getName();

    // Store grabbed strings into the proposed object:
    expectedNames.add(thisExpectedName);
    expectedBreeds.put(thisExpectedBreed, expectedNames);
    expectedTypes.put(thisExpectedType, expectedBreeds);
}

This is almost doing what I want. The HashMaps get set up fine, but at the bottom level they're all storing the same expectedNames array. It looks like this:

- dog
  - beagle
    - 0 charlie
    - 1 chester
    - 2 goldie
    - 3 lord quackerton
  - retriever
    - 0 charlie
    - 1 chester
    - 2 goldie
    - 3 lord quackerton
- duck
  - mallard
    - 0 charlie
    - 1 chester
    - 2 goldie
    - 3 lord quackerton

But here's what I need:

- dog
  - beagle
    - 0 charlie
    - 1 chester
  - retriever
    - 0 goldie
- duck
  - mallard
    - 0 lord quackerton

I think I need to see if thisExpectedBreed at i already exists and if it doesn't, make a new array and put that in the HashMap. But how can I do that? How can I make sure each expectedBreeds Map has its own unique array and add the values to each array correctly?

If it helps, the data set is sorted by type, then breed, then name, so the logic won't have to anticipate any jumping around. Once one breed has been catalogued, for example, I won't have to handle any more elements of that breed.

Was it helpful?

Solution

you need to create a set of names for each map, instead of reusing the same set of names

// Each <animal> element has already been stored in an array called 'zoo'
for( int i = 0; i < zoo.length; i++) 
{
    ...

    // get the names for this breed
    ArrayList<String> expectedNames = expectedBreeds.get(thisExpectedBreed);
    // if there aren't any, start a new collection
    if (expectedNames == null)
    {
        expectedNames = new ArrayList<String>();
        expectedBreeds.put(thisExpectedBreed, expectedNames);
    }
    expectedNames.add(thisExpectedName);
    ...

right now you're reusing the same names across all of the animals

OTHER TIPS

If you want a 1:1 mapping between the XML and a map of maps (of maps...) you are much better off using a tool like Jackson that does the XML -> java object mapping for you. Read about it, you won't be disappointed.

I needed to move the array and internal HashMap instantiations into the loop, as @John Gardner recommended:

// Set up the top-level HashMap
Map<String, Map<String, ArrayList<String>>> expectedTypes = new HashMap();

// Each <animal> element has already been stored in an array called 'zoo'
for( int i = 0; i < tests.length; i++) {
  // Grab string values from XML file, using XMLbeans:
  String thisExpectedType = tests[i].getType();
  String thisExpectedBreed = tests[i].getBreed();
  String thisExpectedName = tests[i].getName();

  // get the breeds for this type:
  Map<String, ArrayList<String>> expectedBreeds = expectedTypes.get(thisExpectedType);
  // if there aren't any, start a new collection:
  if(expectedBreeds == null) {
      expectedBreeds = new HashMap<String, ArrayList<String>>();
      expectedTypes.put(thisExpectedType, expectedBreeds);
  }

  // get the names for this breed:
  ArrayList<String> expectedNames = expectedBreeds.get(thisExpectedBreed);
  // if there aren't any, start a new collection:
  if(expectedNames == null) {
      expectedNames = new ArrayList<String>();
      expectedBreeds.put(thisExpectedBreed, expectedNames);
  }
  expectedNames.add(thisExpectedName);

      expectedBreeds.put(thisExpectedBreed, expectedNames);
      expectedTypes.put(thisExpectedType, expectedBreeds);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top