accand
accand

Reputation: 561

Java HashMap put() strange behaviour

I have created a HashMap with ten fields: the key type is String and the value type is an double[].

When I try to update the map using put(String id, double[] newVal), not only the value associated to the "id" key is updated, but all values in the map.

How to resolve this issue?

      for (int j = 0;j<attrIndex.length;j ++){

        String name = train.attribute(attrIndex [j]).name();
        double g = eval.evaluateAttribute(attrIndex[j]);

        double[] newVal = {0.0, 0.0};
        double w = 1;
        if (g == 0.0) 
            w = 0.5;

        newVal = table.get(name);
        newVal[0] += g;
        newVal[1] += w;
        table.put(name, newVal);

    }

Upvotes: 0

Views: 272

Answers (3)

Stephen C
Stephen C

Reputation: 718758

I'm pretty sure that the real bug is not in the code you have shown us. Consider this:

    double[] newVal = {0.0, 0.0};
    // ...
    newVal = table.get(name);   // LOOK HERE
    newVal[0] += g;
    newVal[1] += w;
    table.put(name, newVal);

At first glance, it looks like you are creating a new double[] and then updating it. But in fact, the double[] that is getting updated is the one that you are pulling from the hash table. (The double[] you are initializing is getting thrown away, and the put operation in your code is redundant.)

So how can this be a problem? Well, by itself it isn't. But it does mean that something else must be populating table with an initial set of entries. And the symptoms would suggest that the code that populates the table looks something like this:

   double[] val = {0.0, 0.0};
   for (String name : ...) {
       table.put(name, val);
   }

... which is creating multiple hash table entries that all share the same double[]. So naturally, when you update the values associated with one name, you are actually updating the values associated with all of the names.


The reason that JB Nizet's (now deleted) code fixed the problem is that it was replacing the double[] object each time it updated an entry.

But a better way to fix this is to change the initialization code to this:

   for (String name : ...) {
       double[] val = {0.0, 0.0};
       table.put(name, val);
   }

And you can simplify your update code to this:

for (int j = 0;j<attrIndex.length;j ++){
    String name = train.attribute(attrIndex [j]).name();
    double g = eval.evaluateAttribute(attrIndex[j]);
    double w = 1;
    if (g == 0.0) 
        w = 0.5;
    double[] val = table.get(name);
    val[0] += g;
    val[1] += w;
}

Upvotes: 2

Gyro Gearless
Gyro Gearless

Reputation: 5279

You only create a single double[], so all key/value pair share the same values.

Try creating a new array:

table.put(name, new double[]{newVal[0], newVal[1]);

Just a quick hack, there are certainly more elegant solutions.

Upvotes: 1

Aniket Thakur
Aniket Thakur

Reputation: 68915

You are using the same array in each iteration of the loop. Change

double[] newVal = {0.0, 0.0};

to

double[] newVal = new double[]{0.0, 0.0};

Upvotes: 1

Related Questions