Combine several arrays into an array of objects in JavaScript
Asked Answered
O

3

6

Say I have three arrays depicting some names, number of books read and how awesome these people [in names] are:

let names = ["Mary", "Joe", "Kenan"];
let numberOfBooks = [2, 1, 4];
let awesomenessLevel = ["pretty cool", "meh", "super-reader"];

I'm trying to use .reduce() to bring them together to create an array of objects containing the relevant index in each array, but I am failing miserably:

    let people = [
    {
       name: "Mary",
       noOfBooks: 2,
       awesomeness: "pretty cool"
    },
    {
       name: "Joe",
       noOfBooks: 1,
       awesomeness: "meh"
    },
    {
       name: "Kenan",
       noOfBooks: 4,
       awesomeness: "super-reader"
    }
  ]

I got it with reduce as well:

let arrFinal = [];

 names.reduce(function(all, item, index) {
  arrFinal.push({
    name: item,
    noOfBooks: numberOfBooks[index],
    awesomeness: awesomenessLevel[index]
  })
}, []);
Outstanding answered 5/4, 2017 at 13:59 Comment(2)
The way you do it with reducedoes not use the benefit of reduce: note how the callback does not return a value, and the all accumulator is not used, which are typical hallmarks of opting for reduce. You can just replace reduce with forEach in that code (and adjust the arguments -- without all), and it would not make a difference.Coryden
you're completely right, I just added them desperately :s. I guess I need to work more on how to use reduce properlyOutstanding
C
7

You could do it with map, like this:

let result = names.map( (v, i) => ({
    name: names[i], 
    noOfBooks: numberOfBooks[i],
    awesomenessLevel: awesomenessLevel[i]
}));

let names = ["Mary", "Joe", "Kenan"];
let numberOfBooks = [2, 1, 4];
let awesomenessLevel = ["pretty cool", "meh", "super-reader"];

let result = names.map( (v, i) => ({
    name: names[i], 
    noOfBooks: numberOfBooks[i],
    awesomenessLevel: awesomenessLevel[i]
}));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

map works better than reduce in this case, because the number of elements you have in the names array (or any of the two others) is the same as the number of elements you need in the output. In that case it is more natural to use map.

Coryden answered 5/4, 2017 at 14:9 Comment(2)
you're right, I think with reduce there's the extra step of defining an array before whereas here you just load up the result. thanks very much for thisOutstanding
You're welcome ;-). See also some other thoughts about reduce in my comment to your question.Coryden
G
5

Use map to create a 1-to-1 mapping between the input arrays and the output arrays.

let people = names.map(function (e, i) {
    return {name:e, noOfBooks:numberOfBooks[i],awesomeness: awesomenessLevel[i]};
});

let names = ["Mary", "Joe", "Kenan"];
let numberOfBooks = [2, 1, 4];
let awesomenessLevel = ["pretty cool", "meh", "super-reader"];

let people = names.map(function (e, i) {
    return {name:e, noOfBooks:numberOfBooks[i],awesomeness: awesomenessLevel[i]};
});


console.log(people);
Gib answered 5/4, 2017 at 14:6 Comment(1)
Just another useful info: instead of alert in a snippet, use console.log, and then you don't even need to do the JSON.stringify as StackOverflow does that for you :-)Coryden
H
1

You could use a dynamic approach by combining all arrays to one object and use the key names as property names for the result objects in the array

let names = ["Mary", "Joe", "Kenan"],
    numberOfBooks = [2, 1, 4],
    awesomenessLevel = ["pretty cool", "meh", "super-reader"],
    object = { name: names, noOfBooks: numberOfBooks, awesomeness: awesomenessLevel },
    result = Object.keys(object).reduce((r, k) =>
        (object[k].forEach((a, i) =>
            (r[i] = r[i] || {})[k] = a), r), []);

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Heideheidegger answered 5/4, 2017 at 14:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.