Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript seperating array of objects into multiple arrays using map(), and Iterator

  1. Basically I have an array of objects like

    var array = [{x: 10, y: 5, r: 10, ...} ]

There are more fields in the object, but to the point, this is the way I've found to seperate the fields to arrays:

var x = array.map(obj => obj.x);
var y = array.map(obj => obj.y);
// and so on for each field

Works, but seems very inefficient as the number of fields and the array size grows, as this scans the array multiple times. I could use a standard loop, but I do prefer the map() as I think it is more readable in this case. Is it possible to return multiple values from map? I think something like:

var [x, y] = array.map(obj => [obj.x, obj.y]); // should output two arrays

Or anything similar which will be readable (reduce is less readable IMO).

  1. I did notice some newer javascript functions like array.entries() which return an iterator object. How can I implement such functions?
like image 840
user3599803 Avatar asked Jan 02 '19 18:01

user3599803


2 Answers

You could reduce the array and iterate the objects key/value pairs. Then push the values to the array of the given property.

var array = [{ x: 10, y: 5, r: 10 }, { x: 11, y: 6, r: 11 }],
    result = array.reduce((r, o) => {
        Object.entries(o).forEach(([k, v]) => (r[k] = r[k] || []).push(v));
        return r;
    }, Object.create(null));
    
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
like image 127
Nina Scholz Avatar answered Sep 27 '22 02:09

Nina Scholz


So, you were on to the right start with your second attempt:

var [x, y] = array.map(obj => [obj.x, obj.y]);

As you indicate, the first attempt is too inefficient, since you will have to loop through the array multiple times for each field you want to pull out, but you can do everything you want to do using an array's .reduce() method.

I would do the following:

var [x, y] = array.reduce(
    (accum, val) => {
        accum[0].push(val.x);
        accum[1].push(val.y);
        return accum;
    },
    [ [], [] ]
);

What I'm doing is telling the reducer to initialize the accumulator with an empty array of arrays ([ [], [] ]), and when it loops through the array, it will put the .x properties into the first array in the accumulator and the .y properties into the second array. And thanks to destructuring, x will be an array of all the .x properties and y will be an array of all the .y properties.

This approach is easy to extend as your fields grow by adding more empty arrays to the initial accumulator object and making sure in the reducer to push those fields into that new object.

like image 22
Ryan Dabler Avatar answered Sep 25 '22 02:09

Ryan Dabler