Efficient way to convert Object arrays into collection in Javascript

Viewed 57
const myObj = {
 a: [1, 2, 3],
 b: [2, 4, 6],
 c: [10, 20, 30]
}

Into

const myCollection = [
  {a: 1, b: 2, c: 10},
  {a: 2, b: 4, c: 20},
  {a: 3, b: 6, c: 30}
]

I tried combinations of Object.entries, Object.keys and map but I'm always finding myself iterating twice or more over myObj and I'm not happy with any solution I came up with. So what is the most efficient (in terms of time complexity) and elegant way that you can think to achieve that?

5 Answers

Just in case you'd need variable length:

const myObj = {
  a: [1, 2, 3],
  b: [2, 4, 6,8, 10],
  c: [10, 20, 30, 40],
};

let myCollection = [];

Object.keys(myObj).forEach((k) => {
  for (let i = 0; i < myObj[k].length; i++) {
    if (!myCollection[i]) myCollection.push({});
    myCollection[i][k] = myObj[k][i];
  }
});
console.log(myCollection);

That can be done using Array.reduce. I have attached the conversion code.

const myObj = {
 a: [1, 2, 3],
 b: [2, 4, 6],
 c: [10, 20, 30]
}

const myCollection = [
  {a: 1, b: 2, c: 10},
  {a: 2, b: 4, c: 20},
  {a: 3, b: 6, c: 30}
]

const maxLength = Math.max(...Object.values(myObj).map(item => item.length));

const myObjKeys = Object.keys(myObj);
const result = [ ...Array(maxLength).keys() ].map((index) => {
  return myObjKeys.reduce((acc, curKey) => {
    if (myObj[curKey].length > index) {
      acc[curKey] = myObj[curKey][index];
    }
    return acc;
  }, {});
});
console.log(result);

Using ramdajs, I could suggest you a short way like below

const myObj = {
  a: [1, 2, 3],
  b: [2, 4, 6],
  c: [10, 20, 30]
}

const res = R.map(
  R.zipObj(R.keys(myObj)),
  R.values(myObj)
)

console.log(res)
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>

In ramdajs homepage, criteria 3 in What's Different, it cited that

The parameters to Ramda functions are arranged to make it convenient for currying. The data to be operated on is generally supplied last.

You could reduce the entries and map nested arrays.

const
    object = { a: [1, 2, 3], b: [2, 4, 6], c: [10, 20, 30] },
    result = Object
        .entries(object)
        .reduce((r, [k, a]) => a.map((v, i) => ({ ...r[i], [k]: v })), []);

console.log(result);

You can use map() on Object.values and then use reduce() on each value.

const myObj = {
 a: [1, 2, 3],
 b: [2, 4, 6],
 c: [10, 20, 30]
}

let keys = Object.keys(myObj);
const arr = Object.values(myObj).map((a) => a.reduce((ac, a, i) => ({...ac, [keys[i]]:a}), {}));
console.log(arr)

Related