Search code examples
javaarraystreemap

Failed test case, what am I doing wrong?


I've been trying to get this to work, but I'm not quite sure where I'm going wrong. It'll make sense with the test case in a bit. Some things about what I'm doing. The list must have one or more lines. If there's not at least one line, an IllegalArgumentException is thrown. Each line has some kind of String, then a tab character, then a double, then a newline. If any lines don't follow this pattern, then an IllegalArgumentException would also be thrown. This is ideally supposed to work if you made any number of lists, so that's why I attempted it this way

Basically, the program is supposed to get a list, say something like...

California   6
Nevada      11
California   1
California  14
Arizona     21
Utah         2
California   7
Utah        10
Nevada       3
Utah         2

and should return something like this:

California {6, 1, 14, 7} 
Arizona    {21}
Utah       {2, 10, 2}
Nevada     {11, 3}

Note that I only used four for the sake of the example. I'm trying to get it so that it's work with any number of lists. Here is my code...

 public static TreeMap<String, ArrayList<Double>> readTable (Scanner dataSource)
    {

        ArrayList<String> dataFromFile = new ArrayList<String>();

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

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

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

            boolean isDouble;
            String state = "";


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


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

              statePopData.clear();
              state = dataFromFile.get(i);
          } 
          if (statePopData.isEmpty()) {
              map.put(state, statePopData);
          }

        } return map;
}

I keep getting one same value for everything for all the other states in the list and I'm confused as to why this is happening.

Here's the test case I mentioned before...

@Test
    public void testReadTable ()
    {
        try (Scanner scn = new Scanner(
                "Utah\t10\nNevada\t3\nUtah\t2\nCalifornia\t14\nArizona\t21\nUtah\t2\nCalifornia\t7\nCalifornia\t6\nNevada\t11\nCalifornia\t1\n"))
        {
            TreeMap<String, ArrayList<Double>> actual = GraphingMethods.readTable(scn);

            TreeMap<String, ArrayList<Double>> expected = new TreeMap<>();
            ArrayList<Double> azList = new ArrayList<>();
            azList.add(21.0);
            expected.put("Arizona", azList);

            ArrayList<Double> caList = new ArrayList<>();
            caList.add(6.0);
            caList.add(1.0);
            caList.add(14.0);
            caList.add(7.0);
            expected.put("California", caList); 

            ArrayList<Double> nvList = new ArrayList<>();
            nvList.add(11.0);
            nvList.add(3.0);
            expected.put("Nevada", nvList);     

            ArrayList<Double> utList = new ArrayList<>();
            utList.add(2.0);
            utList.add(10.0);
            utList.add(2.0);
            expected.put("Utah", utList);

            assertEquals(expected, actual);
        }
    }

I'm a new programmer, so any advice would be greatly appreciated! I'd love to know what I'm doing wrong so that I can learn more. :)


Solution

  • I think the main problem is you are modifying and inserting the same ArrayList instance for each state. A simple version, without robustness checking might 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;
    

    The computeIfAbsent allows you to add a new ArrayList when you see a new state (Java 8+).

    Another issue is the assertEquals. Since the expected number list data is in a different order than the actual, the ArrayLists are not equal. You could verify the keys and values like this:

        assertEquals(expected.keySet(), actual.keySet());
        expected.forEach((state, list) -> {
            Collections.sort(list);
            Collections.sort(actual.get(state));
            assertEquals(list, actual.get(state));
        });