3

I have two arrays that I want to merge together to one array of objects...

The first array is of dates (strings):

let metrodates = [
 "2008-01",
 "2008-02",
 "2008-03",..ect
];

The second array is of numbers:

let figures = [
 0,
 0.555,
 0.293,..ect
]

I want to merge them to make an object like this (so the array items match up by their similar index):

let metrodata = [
   {data: 0, date: "2008-01"},
   {data: 0.555, date: "2008-02"},
   {data: 0.293, date: "2008-03"},..ect
];

So far I do this like so: I create an empty array and then loop through one of the first two arrays to get the index number (the first two arrays are the same length)... But is there an easier way (in ES6)?

  let metrodata = [];

  for(let index in metrodates){
     metrodata.push({data: figures[index], date: metrodates[index]});
  }
NewToJS
  • 2,011
  • 4
  • 35
  • 62
  • [Don't use `for in` enumerations on arrays!](http://stackoverflow.com/q/500504/1048572) – Bergi Sep 26 '16 at 21:27

2 Answers2

6

The easiest way is probably to use map and the index provided to the callback

let metrodates = [
  "2008-01",
  "2008-02",
  "2008-03"
];

let figures = [
  0,
  0.555,
  0.293
];

let output = metrodates.map((date,i) => ({date, data: figures[i]}));

console.log(output);

Another option is to make a generic zip function which collates your two input arrays into a single array. This is usually called a "zip" because it interlaces the inputs like teeth on a zipper.

const zip = ([x,...xs], [y,...ys]) => {
  if (x === undefined || y === undefined)
    return [];
  else
    return [[x,y], ...zip(xs, ys)];
}

let metrodates = [
  "2008-01",
  "2008-02",
  "2008-03"
];

let figures = [
  0,
  0.555,
  0.293
];

let output = zip(metrodates, figures).map(([date, data]) => ({date, data}));

console.log(output);

Another option is to make a generic map function which accepts more than one source array. The mapping function will receive one value from each source list. See Racket's map procedure for more examples of its use.

This answer might seem the most complicated but it is also the most versatile because it accepts any number of source array inputs.

const isEmpty = xs => xs.length === 0;
const head = ([x,...xs]) => x;
const tail = ([x,...xs]) => xs;

const map = (f, ...xxs) => {
  let loop = (acc, xxs) => {
    if (xxs.some(isEmpty))
      return acc;
    else
      return loop([...acc, f(...xxs.map(head))], xxs.map(tail));
  };
  return loop([], xxs);
}

let metrodates = [
  "2008-01",
  "2008-02",
  "2008-03"
];

let figures = [
  0,
  0.555,
  0.293
];

let output = map(
  (date, data) => ({date, data}),
  metrodates,
  figures
);

console.log(output);
Mulan
  • 129,518
  • 31
  • 228
  • 259
2

If you use lodash, you can use zipWith + ES6 shorthand propery names + ES6 Arrow functions for a one-liner, otherwise see @noami's answer.

const metrodata = _.zipWith(figures, metrodates, (data, date)=> ({ data, date }));
Lyubomir
  • 19,615
  • 6
  • 55
  • 69