1

I would like to keep object keys when reducing a CSV data set using JavaScript's map function (if this is in fact the right approach?)

I have read a top SO thread on preserving keys, but the solutions given require external JS libraries (underscore or lodash). I'd prefer avoiding anything but 'vanila' JS if possible.

For example:

var basket = [{fruit: "apple", veg: "carrot", nut: "peanut"},
 {fruit: "pear", veg: "lettuce", nut: "pistachio"},
 {fruit: "banana", veg: "radish", nut: "pecan"},
 {fruit: "kiwi", veg: "kale", nut: "almond"}]

Yields an array of 3 objects, corresponding to each 'food type' entry above (fruit, veg, nut).

I don't want nuts, so I try using map to filter them out:

var small_basket = basket.map(function(item){
  return [
item.fruit,
item.veg
  ]
});

This approach returns an array of 4 arrays, corresponding to each of the items per food type in my list, e.g. 4 fruits and 4 nuts (so we've effectively eliminated nuts).

My trouble is: now my object keys are gone! Instead, my array now looks like this:

small_basket = Array(3) [
  0: Array(2) [
  0: "apple"
  1: "carrot"
]
  1: Array(2) [
  0: "pear"
  1: "lettuce"
]
  2: Array(2) [
  0: "bananna"
  1: "raddish"
]
]

What can I do differently to preserve object keys?

aaron.kyle
  • 163
  • 3
  • 10

4 Answers4

4

Just return another object:

return {
  fruit: item.fruit,
  veg: item.veg
}

That can be shortly written as:

 array.map(({ fruit, veg }) => ({ fruit, veg }))

or if you don't want to duplicate identifiers:

 const pick = (key, ...rest) => obj => key ? ({ [key]: obj[key], ...pick(...rest)(obj) }): {};
 array.map(pick("fruit", "veg"))

or to invert the extraction into a removal:

 array.map(({ nut, ...rest }) => rest)
Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
  • The removal [ `...rest` ] approach is terrific for not having to repeat the object key values that I wish to retain on both sides of the arrow function, but it's working from the opposite end: stating which variables to delete. It doesn't appear from the several answers to my question that there's a way to specify only once the list of key values one wishes to retain. Is there? – aaron.kyle Apr 05 '19 at 13:49
  • @aaron.kyle that is only possible with a helper. – Jonas Wilms Apr 05 '19 at 20:46
2

From the .map callback, return an object containing the keys you want, instead of returning an array:

var basket = [{fruit: "apple", veg: "carrot", nut: "peanut"},
 {fruit: "pear", veg: "lettuce", nut: "pistachio"},
 {fruit: "banana", veg: "radish", nut: "pecan"},
 {fruit: "kiwi", veg: "kale", nut: "almond"}]

var small_basket = basket.map(({ fruit, veg }) => ({ fruit, veg }));
console.log(small_basket);
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
1

In the map functions, the returning value is always the child of your Array. In you case, you should return a Object, because your child element in Array is Object, returning array will make your child element was map to array.

I think the code below will match you needs:


basket.map(function(item){
  return { fruit: item.fruit, veg: item.veg }
});

That is so reduntant. Using ES 6 Destucting, you may simply write like this:


basket.map(function({ nut, fruits, veg}){
  return { fruits, veg }
});

But the way above will be not much elasticity, using ES 6 rest parameter, you may simply write like this:


basket.map(function({ nut, ...restFoodType }){
  return { ...restFoodType }
});

1

Alternatively, if you want to keep the ref and know how delete works:

var basket = [{
    fruit: "apple",
    veg: "carrot",
    nut: "peanut"
  },
  {
    fruit: "pear",
    veg: "lettuce",
    nut: "pistachio"
  },
  {
    fruit: "banana",
    veg: "radish",
    nut: "pecan"
  },
  {
    fruit: "kiwi",
    veg: "kale",
    nut: "almond"
  }
];

basket.forEach(x => delete x.nut);

console.log(basket)
Ferenc
  • 527
  • 3
  • 6