2

Assume...

let A = [{ x:'x', y:'y' }, { x:'x', y:'y' }];

I know I can transform this array into a new one taking and renaming the y property like this...

A.map(o => ({ v: o.y }));
// [{ v:'y' }, { v:'y' }]

And I can use a spread to get all existing properties plus a new, transformed one like this...

A.map(o => ({ ...o, ...{ v: o.y } }));
// [{ x:'x', y:'y', v:'y' }, { x:'x', y:'y', v:'y' }]

But I'm wondering if there's an elegant way to simply rename the y property to v. So here's what I want.

// [{ x:'x', v:'y' }, { x:'x', v:'y' }]

I know I can use a function block on my fat arrow function, add a v property, and delete the y property, but that's cumbersome. I'm looking for something elegant.

Jeremy Foster
  • 4,673
  • 3
  • 30
  • 49

4 Answers4

6

You can use Array.map() and Object destructing :

let A = [{ x:'x', y:'y' }, { x:'x', y:'y' }];

let result = A.map(({y,...rest})=> ({...rest,v:y}));

console.log(result);
amrender singh
  • 7,949
  • 3
  • 22
  • 28
5

You could rename the property and use the rest syntax for an object to get all other properties. For mapping take the rested parameters and the new property.

let A = [{ x: 'x', y: 'y' }, { x: 'x', y: 'y' }];

console.log(A.map(({ y: v, ...o }) => ({ ...o, v })));
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
1

I know you said you knew you could delete, but it doesn't necessarily have to be inelegant if you're looking to alter the objects in place:

let A = [{ x:'x', y:'y' }, { x:'x', y:'y' }];

A.forEach(o => delete Object.assign(o, {v: o.y }).y)
console.log(A)
Mark
  • 90,562
  • 7
  • 108
  • 148
  • 1
    As an aside here, this will degrade performance on large sets due to delete triggering dictionary mode in most JavaScript engines. On small sets, this is clearly not an issue. – Travis J Nov 01 '18 at 20:28
  • That's interesting @TravisJ, thanks — I didn't know that. – Mark Nov 01 '18 at 20:36
  • This made me curious @TravisJ, so I found [this old thread](https://stackoverflow.com/questions/23455678/pros-and-cons-of-dictionary-mode) which pointed to [this jsperf test](https://jsperf.com/test-dictionary-mode). In the test `delete` is significantly slower in Safari, but the performance is essentially identical in Chrome. I wonder if recent changes to V8 have made this less significant. – Mark Nov 01 '18 at 21:55
  • That still uses delete, the perf is the same. Please see erfr of the 16th revision https://jsperf.com/test-dictionary-mode/17 for the comparison without delete. It is 32% faster. – Travis J Nov 01 '18 at 23:04
0

This approach provides a less hard-coded way to convert keys into new ones. On the other hand, this [mapping[k]] is called Computed property names.

Likewise, the function Array.prototype.reduce is building the desired object according to the mapping and the specific object itself.

Important: The function Array.prototype.map is creating a new Array, basically is not modifying/mutating the original array.

let A = [{ x:'x', y:'y' }, { x:'x', y:'y' }];
    mapping = {'y': 'v'},    
    result = A.map(o => Object.keys(o).reduce((a, k) => {
      if (k in mapping) return Object.assign(a, {[mapping[k]]: o[k]});
      return Object.assign(a, {[k]: o[k]});
    }, Object.create(null)));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Ele
  • 33,468
  • 7
  • 37
  • 75