Nanobrain91
Nanobrain91

Reputation: 55

Convert an object with multiple values per key into array of objects in JS

I have an object that looks like this:

 obj={"a": [1,2],"b": [3,4],"c": [5,6]}

I need to create an array of objects where every object consists of each key with only one value corresponding to its order like this:

obj2=[{"a": 1, "b": 3, "c": 5},{"a": 2, "b": 4, "c": 6}]

Also, if I have a JSON string using JSON.stringify(obj), would it be somehow possible to create string corresponding to JSON.stringify(obj2) directly from the first one?

Upvotes: 1

Views: 6394

Answers (6)

mpm
mpm

Reputation: 20155

const obj = { "a": [1, 2], "b": [3, 4], "c": [5, 6] }
// create an array to store result
const result = []
// for each key in obj
Object.keys(obj).forEach(key => {
    // for each array element of the property obj[key]
    obj[key].forEach((value, index) => {
        // if an object doesn't exists at the current index in result
        // create it
        if (!result[index]) {
            result[index] = {}
        }
        // at the result index, set the key to the current value
        result[index][key] = value
    })
})
console.log(result)

Here is my algorithm, given the expected result .

Also, let's say i have a JSON string using JSON.stringify(obj), would it be somehow possible to create string corresponding to JSON.stringify(obj2) directly from the first one?

Yes, you could add .toJSON to obj:

const obj = { "a": [1, 2], "b": [3, 4], "c": [5, 6] }
Object.setPrototypeOf(obj, {
    toJSON: function () {
        const result = []
        Object.keys(this).forEach(key => {
            this[key].forEach((value, index) => {
                if (!result[index]) {
                    result[index] = {}
                }
                result[index][key] = value
            })
        })
        return JSON.stringify(result);
    }
})



console.log(JSON.stringify(obj))

You can use Object.setPrototypeOf so that toJSON method is not counted as an enumerable key when Object.keys(obj).forEach iterates

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/setPrototypeOf

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#toJSON()_behavior

Upvotes: 1

Leonid Pyrlia
Leonid Pyrlia

Reputation: 1712

You can iterate over the keys of the input object and construct the desired output with Array.prototype.reduce

var obj={"a": [1,2],"b": [3,4],"c": [5,6]};

var result = Object.keys(obj).reduce((a, k) => (obj[k].forEach((n, i) => a[i] = {...(a[i] || {}), ...{[k]: n}}), a),[]);
  
console.log(result);

Upvotes: 0

Nina Scholz
Nina Scholz

Reputation: 386600

You could use a single loop for the keys and another for the value and map a new array.

This works for same length arrays.

var object = { a: [1, 2], b: [3, 4], c: [5, 6] },
    array = Object
        .entries(object)
        .reduce((r, [k, a]) => a.map((v, i) => Object.assign(r[i] || {}, { [k]: v })), []);
        
console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 0

Eddie
Eddie

Reputation: 26844

You can use Object.keys and Object.values to extract the keys and the values. Use Math.max to get the max length of the values. Use for to loop thru and use reduce to make new object.

var obj = {"a": [1, 2],"b": [3, 4],"c": [5, 6]};

var keys = Object.keys(obj);
var values = Object.values(obj);

var obj2 = [];

for (i = 0; i < Math.max(...values.map(o => o.length)); i++) {
  obj2.push(keys.reduce((c, v, k) => Object.assign(c, {[v]: values[k][i] || ""}), {}))
}

console.log(obj2);

This will work even if the given object values are not the same on length.

var obj = {
  "a": [1, 2],
  "b": [3, 4],
  "c": [5, 6, 10]
};

var keys = Object.keys(obj);
var values = Object.values(obj);

var obj2 = [];

for (i = 0; i < Math.max(...values.map(o => o.length)); i++) {
  obj2.push(keys.reduce((c, v, k) => Object.assign(c, {[v]: values[k][i] || ""}), {}))
}

console.log(obj2);

Upvotes: 1

Daria Pydorenko
Daria Pydorenko

Reputation: 1802

If your values (arrays) have the same length.

obj = {"a": [1,2],"b": [3,4],"c": [5,6]};
obj2 = [];

var keys = Object.keys(obj)

for (i = 0; i < obj[keys[0]].length; i++) {
    temp = {};
    keys.forEach(x => temp[x] = obj[x][i]);
    obj2.push(temp);
}

console.log(obj2);

Upvotes: 0

OliverRadini
OliverRadini

Reputation: 6467

I believe this should do the trick:

obj={"a": [1,2],"b": [3,4],"c": [5,6]}
 
const transform = input => Object.values(input)[0]
  .map((_, i) => Object.keys(input)
    .reduce((prev, curr) => {
      prev[curr] = input[curr][i]
      return prev
    }, {}))
    
const result = transform(obj)

console.dir(result)

This will only work on objects where each value is an array of the same length. You take each index of the first value, then create an object for each key, getting the value using the aforementioned index.

Upvotes: 0

Related Questions