1

I have a table that has two columns, one is string and other is double type. for example,

+========+=============+
| Center | Efficiency  |
+========+=============+
| A1     | 0.603576904 |
+--------+-------------+
| A2     | 0.557877389 |
+--------+-------------+
| A3     |  0.70911818 |
+--------+-------------+
| A4     | 0.048944132 |
+--------+-------------+
| A1     | 0.064781491 |
+--------+-------------+
| A2     | 0.192317935 |
+--------+-------------+
| A3     | 0.316078683 |
+--------+-------------+
| A4     | 0.121362541 |
+--------+-------------+
| A1     | 0.815996499 |
+--------+-------------+
| A2     | 0.032305255 |
+--------+-------------+
| A3     | 0.750355015 |
+--------+-------------+
| A4     | 0.071286058 |
+--------+-------------+

I'm trying to read all the values and load them into a Java HashMap<String, Double[]>

I don't have any problem with reading table data but can not place them into the HashMap as I wanted.

I wrote a sample code to populate a HashMap from two different arrays of string and double but still confused to work with the value part of the Hashmap which is an array.

  String[] names = { "8A", "8C", "8J", "8A", "8C", "8J", "8A", "8C", "8J", "8A", "8C", "8J", };

  Double[] metrics = { 0.60, 0.55, 0.70, 0.04, 0.06, 0.19, 0.31, 0.12, 0.81, 0.03, 0.75, 0.07 };

  for (int i = 0; i < 12; i++)
  {
     if (values.get(names[i]) == null)
     {
        values.put(names[i], new ArrayList<Double>(Arrays.asList(metrics[i])));
     }
     else
        values.get(names[i]).add(metrics[i]);
  }

  System.out.println(values);

Any suggestion how can I handle with the value part of the HashMap which is an array and the size will depend on the table row numbers.

User_67128
  • 1,230
  • 8
  • 21
  • If `values` is the Map, `values.put(names[i],metrics[i])`, assuming both have the same size. – PythonLearner Nov 27 '19 at 15:47
  • @ManojBanik I proposed a HashMap version, but why do you actually want that instead of HashMap>? Some interface issues, where you can't pass on lists or performance maybe? If its the latter, the HashMap version would be better. – Curiosa Globunznik Nov 27 '19 at 16:41
  • Some other part of the code used Array for the value part, now I'm trying to finish my part with less change, but looks like List is less hassle in my case. Thanks. @gurioso – User_67128 Nov 27 '19 at 16:44

3 Answers3

2

Nowadays Map has some convenience methods and you can use computeIfAbsent:

Map<String, List<Double>> values = new HashMap<>();
        for (int i = 0; i < 12; i++) {
            List<Double> items = values.computeIfAbsent(names[i], k -> new ArrayList<>());
            items.add(metrics[i]);
        }

There's a more elaborate post about that here.

But if you want to have an Map<String, double[]> then that's very inconvenient during loading, since arrays have fixed size and you'd need to copy them over and over. You could arrive at double[] using the list version for loading and eventually convert it

Map<String, double[]> dvalues = new HashMap<>();
values.forEach((k, v) -> dvalues.put(k, v.stream().mapToDouble(i -> i).toArray()));

Or if it should be a Double[]

Map<String, Double[]> dvalues = new HashMap<>();
values.forEach((k, v) -> dvalues.put(k, v.toArray(new Double[v.size()])));

The only alternative I see is to iterate over the raw data twice, first calculating the number of values for each key, create a map from that with properly sized arrays, iterate again over the raw data keeping track of the maxIdx in each value array as they fill up ... very complicated.

Curiosa Globunznik
  • 3,129
  • 1
  • 16
  • 24
1

What Deb said. You can't use .add(...) on top of .get(...) method to change the map content. You have to explicitly use .put(...) method.

Sunny Patel
  • 107
  • 1
  • 7
1

You can check if key exist :

  • if it is, just get the array list, and put the metric in there
  • if not, create an array list, add the metric and put the key, list in the map

like this :

        for (int i = 0; i < 12; i++)
        {
            String key = names[i];
            double metric = metrics[i];

            if (values.containsKey(key)) {
                values.get(key).add(metric);

                /* same as : 
                ArrayList<Double> d = values.get(key);
                d.add(metric)
                */
            } else {
                ArrayList<Double> newlist = new ArrayList<>();
                newlist.add(metric);
                values.put(key, newlist);
            }
        }

This assumes that both have the same size obviously.

Update for Array : An "okay" solution would be to create a new one each time you insert a value with a size + 1 that the previous one.

        HashMap<String, double[]> values = new HashMap<>(  );

        String[] names = { "8A", "8C", "8J", "8A", "8C", "8J", "8A", "8C", "8J", "8A", "8C", "8J", };

        Double[] metrics = { 0.60, 0.55, 0.70, 0.04, 0.06, 0.19, 0.31, 0.12, 0.81, 0.03, 0.75, 0.07 };

        for (int i = 0; i < 12; i++)
        {
            String key = names[i];
            double metric = metrics[i];

            if (values.containsKey(key)) {
                double[] oldArray = values.get(key);
                double[] newArray = new double[oldArray.length + 1];

                System.arraycopy(values.get(key), 0, newArray, 0, oldArray.length);

                values.put( key, newArray );
            } else {
                values.put( key, new double[] { metric } );
            }
        }
Lucsartes
  • 321
  • 2
  • 13