15

How should I replace the key strings in a Javascript key:value hash map (as an object)?

This is what I have so far:

var hashmap = {"aaa":"foo", "bbb":"bar"};
console.log("before:");
console.log(hashmap);

Object.keys(hashmap).forEach(function(key){
   key = key + "xxx";
   console.log("changing:");
   console.log(key);
});

console.log("after:");
console.log(hashmap);

See it running in this jsbin.

The "before" and "after" hashmaps are the same, so the forEach seems to be in a different scope. How can I fix it? Perhaps there are better ways of doing this?

msanford
  • 11,803
  • 11
  • 66
  • 93
HaoQi Li
  • 11,970
  • 14
  • 58
  • 77

5 Answers5

29

It has nothing to do with scope. key is just a local variable, it's not an alias for the actual object key, so assigning it doesn't change the object.

Object.keys(hashmap).forEach(function(key) {
  var newkey = key + "xxx";
  hashmap[newkey] = hashmap[key];
  delete hashmap[key];
});
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • 3
    Note that this only works if all the new keys are different from the old key, like in this example, or else the key would be deleted entirely. – HaoQi Li Jul 09 '13 at 18:19
  • 1
    @HaoQiLi Quite true. A safer algorithm would involve copying the object to a new object, then copying back. Feel free to post answer like that. – Barmar Jul 09 '13 at 18:39
3

if keys order is important you can use:

const clone = Object.fromEntries(
  Object.entries(o).map(([o_key, o_val]) => {
    if (o_key === key) return [newKey, o_val];
    return [o_key, o_val];
  })
);

this will create an object with the new key in the same place where the old one was.

Behemoth
  • 5,389
  • 4
  • 16
  • 40
Ori Lerman
  • 31
  • 4
1

You are just changing the copy of the object's keys, so the original object won't be changed. You can create an new object to hold the new keys, like this:

var hashmap = {"aaa":"foo", "bbb":"bar"};
console.log("before:");
console.log(hashmap);

var newHashmap = {};
Object.keys(hashmap).forEach(function(key){
    var value = hashmap[key];

    key = key + "xxx";
    console.log("changing:");
    console.log(key);

    newHashmap[key] = value;
});

console.log("after:");
console.log(newHashmap);
Finian Lau
  • 231
  • 2
  • 8
1

Update

This way is better, in my opinion.

const hashmap = { aaa: 'foo', bbb: 'bar' };

const newHashmap = Object.fromEntries(
  Object
    .entries(hashmap)
    .map(([k, v]) => [`${k}xxx`, v]),
);

console.log(newHashmap);
// { aaaxxx: 'foo', bbbxxx: 'bar' }

Previous

You can use Array.prototype.reduce().

const hashmap = { aaa: 'foo', bbb: 'bar' };

const newHashmap = Object.entries(hashmap).reduce((acc, [key, value]) => ({
  ...acc,
  [`${key}xxx`]: value,
}), {});

console.log(newHashmap);
// { aaaxxx: 'foo', bbbxxx: 'bar' }
onosendi
  • 1,889
  • 1
  • 7
  • 14
0

The function takes as an argument the original map and returns a new one with the keys altered. The call of the mapT(m) just returns the transformed map with the new keys.

function mapT(map){
    const x = new Map();
    for (const [k, v] of map) {
      x.set(k+ "xxx", v);
    }    
    return x;
}

Simple call : var new_map = mapT(mapA);
Stathis Andronikos
  • 1,259
  • 2
  • 25
  • 44