Razvan Zamfir
Razvan Zamfir

Reputation: 4614

Why can't I return an array of objects with only certain keys from this array of objects?

I got stuck while working on a function that should return an array of objects from another array of objects. As can be seen below, I use only one key and return a "simple" array instead of an array of objects:

function pluck(array, key) {
  return array.map(x => x[key]);
}

var myArr = [{
  name: "United Kingdom",
  alpha3: "GBR",
  code: "GB",
  region: "Europe",
  tax: 5,
  status: 1
}, {
  name: "Romania",
  alpha3: "ROM",
  code: "RO",
  region: "Europe",
  tax: 3,
  status: 1
}];

myArr = pluck(myArr, 'name');

console.log(myArr);

If I use 2 (or more) keys, I still get a "simple" array of values corresponding to the last key used:

function pluck(array, key1, key2) {
  return array.map(x => x[key1, key2]);
}

var myArr = [{
  name: "United Kingdom",
  alpha3: "GBR",
  code: "GB",
  region: "Europe",
  tax: 5,
  status: 1
}, {
  name: "Romania",
  alpha3: "ROM",
  code: "RO",
  region: "Europe",
  tax: 3,
  status: 1
}];

myArr = pluck(myArr, 'name', 'code');

console.log(myArr);

What I want is:

var myArr = [
  {name: "United Kingdom", code: "GB"},
  {name: "Romania", code: "RO"}
]

What is missing?

Upvotes: 1

Views: 163

Answers (2)

CherryDT
CherryDT

Reputation: 29012

x[key1, key2] won't do what you want, because key1, key2 will evaluate to key2 (since it would use the comma operator).

Plus, you are currently creating an array with just the values, not with objects that contain the relevant keys and values.

You can use the way TKoL showed for 2 keys, or you could generalize it into a function that can take any number of keys:

function pluck (array, ...keys) {
  return array.map(x =>
    keys.reduce((obj, key) =>
      Object.assign(obj, { [key]: x[key] }),
    {})
  )
}

var myArr = [{
  name: "United Kingdom",
  alpha3: "GBR",
  code: "GB",
  region: "Europe",
  tax: 5,
  status: 1
}, {
  name: "Romania",
  alpha3: "ROM",
  code: "RO",
  region: "Europe",
  tax: 3,
  status: 1
}];

myArr = pluck(myArr, 'name', 'code');

console.log(myArr);

This uses ...keys to define keys as a rest argument that contains all the remaining arguments as an array. Later we iterate over this array of keys to assemble the desired object for each element: reduce is called with {} as initial value, and for every iteration it adds one of the keys to the object and returns the final object at the end. Object.assign(obj, { [key]: x[key] }) is used instead of { ...obj, [key]: x[key] } to avoid unnecessary creation of a new object every time.

An alternative, more imperative way of writing this function would be using a for loop:

function pluck (array, ...keys) {
  return array.map(x => {
    const obj = {}
    for (const key of keys) {
      obj[key] = x[key]
    }
    return obj
  })
}

Upvotes: 4

TKoL
TKoL

Reputation: 13892

function pluck(array, key1, key2) {
  return array.map(x => ({
    [key1]: x[key1],
    [key2]: x[key2]
  }));
}

var myArr = [{
  name: "United Kingdom",
  alpha3: "GBR",
  code: "GB",
  region: "Europe",
  tax: 5,
  status: 1
}, {
  name: "Romania",
  alpha3: "ROM",
  code: "RO",
  region: "Europe",
  tax: 3,
  status: 1
}];

myArr = pluck(myArr, 'name', 'code');

console.log(myArr);

Seems like you meant to do something like that. You could make it more generalized by the second parameter being an array of keys, and inside the map function iterating over each key and adding it to the object one by one.

Upvotes: 5

Related Questions