Search code examples
javaarraylisttreemap

Populating TreeMap<String, ArrayList(of different lengths) > with <ArrayList> data


My function takes in a Scanner and returns a TreeMap map with Strings as keys, and an ArrayList as a value. These ArrayLists can be of different lengths. I've parsed the Scanner to a new ArrayList textData for easier iteration. The procedure should go as follows:

  1. If the element is a String, have that be the new key to the next TreeMap entry (stored as String state) and clear the temporary array
  2. If the element is parseable to a Double, add it to the temporary ArrayList statePopData.
  3. Commit to map.

Ideally, with the scanner :

"Utah\t6.0\t60\n" + "California\t5\t30\n" + "Nevada\t3"

should return:

{"Utah",[6.0, 60.0], "California",[5.0, 30.0], "Nevada",[3.0],}

Here is what I have thus far:

 public static TreeMap<String, ArrayList<Double>> readTable (Scanner dataSource)
{
        //Parse Scanner to ArrayList
    ArrayList<String> textData = new ArrayList<String>();

    while(dataSource.hasNext()){
        textData.add(dataSource.next());
   }

    //Populate TreeMap
    ArrayList<Double> statePopData = new ArrayList<>();
    TreeMap<String, ArrayList<Double>> map = new TreeMap<>();

    for (int i = 0; i < textData.size(); i++) {

        boolean isDouble;
        String state = "";


      try {
          Double.parseDouble(textData.get(i));
          isDouble = true;
      } catch (NumberFormatException | NullPointerException nfe) {
          isDouble = false;
      }


      if(isDouble) {
          statePopData.add(Double.parseDouble(textData.get(i)));
      } else { //means its a string

          statePopData.clear();
          state = textData.get(i);
      } 

      if (statePopData.isEmpty()) {
          map.put(state, statePopData);
      }

    } return map;}

I feel confident with the pieces, but I can never seem to run the map.put() statement at the right time with the proper values to commit. For example, my current results of the program are: {California=[3.0], Nevada=[3.0], Utah=[3.0]}

EDIT: The linked answer doesn't involve any implementation nor fully answers what I'm trying to do.


Solution

  • Looks like duplicate code to Failed test case, what am I doing wrong?
    The same ArrayList instance is being modified and set for each state, so it is being cleared and overwritten each time. A simpler approach may be:

        TreeMap<String, ArrayList<Double>> map = new TreeMap<>();
        while (dataSource.hasNext()) {
            String state = dataSource.next();
            Double d = Double.parseDouble(dataSource.next());
            map.computeIfAbsent(state, k -> new ArrayList<>()).add(d);
        }
        return map;
    

    Updated solution for state followed by multiple numbers:

    // Usually better to use List than ArrayList for declared generic types
    public static TreeMap<String, List<Double>> readTable(Scanner dataSource) {
        TreeMap<String, List<Double>> map = new TreeMap<>();
        String state = null;
        while (dataSource.hasNext()) {
            String next = dataSource.next(); // Should never be null
            try {
                Double d = Double.parseDouble(next);
                // Ignores numbers received before state is set
                if (state != null)
                    // If state has been set, list that must have been initialized
                    map.get(state).add(d); 
            } catch (NumberFormatException e) {
                // Assumes any non-double is a state
                state = next;
                // Initialize map entry with empty list
                map.put(state, new ArrayList<>());
            }
        }
        return map;
    }