How to form This JSON from this Javascript array of arrays? - javascript

I have this JavaScript array of arrays
arr1= [
['a', 'b'],
['1', '2']
]
And I need to form this JSON object
[
{
"label":"a",
"value":"1"
},
{
"label":"b",
"value":"2"
},
]
How do I do it?

Using Array#map:
const arr = [ ['a', 'b'], ['1', '2'] ];
const [labels, values] = arr;
const res = labels.map((label, index) => ({ label, value: values[index] }));
console.log(res);

Look at this ...
const entries = new Map([
['foo', 'bar'],
['baz', 42]
]);
const obj = Object.fromEntries(entries);
console.log(obj);
// expected output: Object { foo: "bar", baz: 42 }
Did you mean something like this?
Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/fromEntries

You could take an array with the keys of the wanted objects and reduce and map the items.
const
data = [['a', 'b'], ['1', '2']],
keys = ['label', 'id'],
result = data.reduce((r, a, i) => a.map((v, j) => ({ ...r[j], [keys[i]]: v })), []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related

Flatten arrays in an object

I have an object as below:
const USER_MAP = {
PREMIUM: ['a', 'b'],
RETAIL: ['c', 'd']
};
I would like to transform to below
[
{ segment: 'PREMIUM', id: 'a' },
{ segment: 'PREMIUM', id: 'b' },
{ segment: 'RETAIL', id: 'c' },
{ segment: 'RETAIL', id: 'd' }
]
I came up with a solution as below
const USER_MAP = {
PREMIUM: ['a', 'b'],
RETAIL: ['c', 'd']
};
const userList = Object.entries(USER_MAP).reduce((accumulator, currentValue) => {
const userListByType = currentValue[1].map(id => ({ id, segment: currentValue[0]}))
return [...accumulator, ...userListByType]
}, []);
console.log(userList);
It works but im wondering if there might be a better way to achieve above? In terms of readability as I'm nesting a map in a reduce, it seems to me that I might've complicated stuffs here
You could take Array#flatMap with a mapping of nested objects with outer key.
const
USER_MAP = { PREMIUM: ['a', 'b'], RETAIL: ['c', 'd'] },
result = Object
.entries(USER_MAP)
.flatMap(([segment, a]) => a.map(id => ({ segment, id })));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Spread an object into a table

I'm looking for a simple (and hopefully neat) way to convert an object of this form:
const object = {
key1: [a, b],
key2: [x, y, z]
};
To this:
[key1, a, key1, b, key2, x, key2, y, key2, z]
What I have so far is this:
const table = Object.entries(object).map(entry => [entry[0], ...entry[1]]);
Which gives me this:
[key1, a, b, key2, x, y, z]
How can I move forward?
You could take the entries of the object using Object.entries() and use a double nested .flatMap() one mapping the entries, and the other for mapping the actual value arrays to be [key, value] pairs like so:
const object = {
key1: ['a', 'b'],
key2: ['x', 'y', 'z']
};
const res = Object.entries(object).flatMap(([k, vals]) => vals.flatMap(v => [k, v]));
console.log(res);
Without flatMap you can use .concat() and .reduce() along with the spread syntax (...):
const object = {
key1: ['a', 'b'],
key2: ['x', 'y', 'z']
};
const res = Object.entries(object).reduce(
(acc, [key, vals]) => acc.concat(...vals.map(v => [key, v])), []);
console.log(res);
You can use Array.reduce on the object entries, pushing a key/value pair to the accumulator for each entry in the value:
const object = {
key1: ['a', 'b'],
key2: ['x', 'y', 'z']
};
const result = Object.entries(object)
.reduce((c, [k, a]) => {
a.forEach(v =>
c.push(k, v)
);
return c;
}, []);
console.log(result);
You can easily do that without using flat() method. You can do that using reduce and forEach to achieve this.
obj = {'key1': [1,2,3], 'key2': [4,5,6]};
ret = Object.keys(obj).reduce((prev, curr) => {
obj[curr].forEach(item => { prev = [...prev, curr, item]; });
return prev;
}, []);
console.log(ret);
On old Node versions, you can use Array#concat and spread syntax [].concat(...array) to flatten arrays, using the same overall approach as other answers:
const object = {
key1: [1, 2],
key2: [3, 4, 5]
};
const result = [].concat(
...Object.entries(object)
.map(([k, v]) =>
[].concat(...v.map(e => [k, e]))
)
);
console.log(result);
If you flatten things often, you can make it a function and bury it in your utilities file so it reads a bit cleaner:
const flat = a => [].concat(...a);
const flatMap = (a, fn) => flat(a.map(fn));
const object = {
key1: [1, 2],
key2: [3, 4, 5]
};
const result = flatMap(
Object.entries(object),
([k, v]) => flatMap(v, e => [k, e])
);
console.log(result);
Method 1, Using Object.entries, map and flat
Method 2, Using Object.entries, forEach and push
const object = {
key1: ["a", "b"],
key2: ["x", "y", "z"],
};
// Method 1, Using Object.entries, map and flat
const res = Object.entries(object)
.map(([key, arr]) => arr.map((value) => [key, value]))
.flat(2);
// Method 2, Using Object.entries, forEach and push
const toArr = (obj) => {
const res = [];
Object.entries(object).forEach(([key, arr]) =>
arr.forEach((value) => res.push(key, value))
);
return res;
};
console.log(res)
console.log(toArr(object));
using map and flat() you can achieve the result
const object = {
key1: ['a', 'b'],
key2: ['x', 'y', 'z']
};
Object.keys(object).map((e, i )=> {
return Object.values(object[e]).map( v => { return [e, v]}).flat()
}).flat()
// ["key1", "a", "key1", "b", "key2", "x", "key2", "y", "key2", "z"]
The most concise, clean and elegant way would be to combine Object.entries() and flat() with a degree sent as a parameter to the flat method.
Note: flat()- works on an array and flattens the array to the degree sent in the params. It returns a new flatten array. For example:
let arr = [1, 2, [3]];
let arrDegree1 = arr.flat();
console.log(arrDegree1) //[1,2,3];
let arr2 = [1, 2, [[3]]]
let arrDegreeTwo = arr2.flat(2);
console.log(arrDegreeTwo) //[1,2,3];
Thus Solution for this would be:
const o = {
key1: ['a', 'b'],
key2: ['x', 'y', 'z']
};
const result = Object.entries(o).reduce((acc,[key, values])=>{
return [...acc, (values.map(v=> [key,...v])) ];
},[]).flat(2);
console.log("Result",result);

How to map an array of arrays into an array of objects with a given keys array?

From an array of keys and an array of arrays, like this:
const keys = ['foo', 'bar'];
const vals = [
['a', 'A'],
['b', 'B']
];
How to get an array of objects like below ?
[
{'foo' : 'a', 'bar' : 'A'},
{'foo' : 'b', 'bar' : 'B'}
]
Maybe using lodash ?
You can use loash's _.zipObject() to create an object from an array of keys and values for each value array inside your 2d array using the _.map() method:
const keys = ['foo', 'bar']
const vals = [
['a', 'A'],
['b', 'B']
];
const res = _.map(vals, arr => _.zipObject(keys, arr));
console.log(res);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>
If you prefer vanilla JS, then you could use Object.fromEntries() on a zipped array (created using .map()):
const keys = ['foo', 'bar']
const vals = [
['a', 'A'],
['b', 'B']
];
const res = vals.map(
arr => Object.fromEntries(arr.map((v, i) => [keys[i], v]))
);
console.log(res);
To be more generic, you can use Array.reduce() with index variable
const keys = ['foo', 'bar']
const values = [
['a', 'A'],
['b', 'B']
]
const mapped = values.map(val => val.reduce((acc, cur, i) => ({...acc, [keys[i]]: cur}),{}))
console.log(mapped)
With lodash/fp you can generate a function using _.flow(), that curries _.zipObject() with the keys, and the _.map() with the curried _.zipObject(), and then you can call it with vals to get the array of objects:
const fn = _.flow(_.zipObject, _.map);
const keys = ['foo', 'bar']
const vals = [
['a', 'A'],
['b', 'B']
];
const result = fn(keys)(vals);
console.log(result);
<script src='https://cdn.jsdelivr.net/g/lodash#4(lodash.min.js+lodash.fp.min.js)'></script>
You can do it simply using reduce.
let keys = ['foo', 'bar'];
let values = [
['a', 'A'],
['b', 'B']
];
const res = values.reduce((a, [first, second]) => {
return [...a, {[keys[0]]: first, [keys[1]]: second}];
}, []);
console.log(res);
.as-console-wrapper{min-height: 100%!important; top:0}
let dataKeys = ['foo', 'bar'];
let dataValues = [
['a', 'A'],
['b', 'B']
];
let transformed = dataValues.reduce((result,item)=>{
result.push(
dataKeys.reduce((r,dk,index)=>{
let o = {};
o[dk]= item[index];
return {...r, ...o}
},{})
)
return result
},[]);
console.log(JSON.stringify(transformed,null,2));

Nested array manipulation

I have below two array:
var val = [['aa', 'ab', 'ac'], ['bb', 'bc', 'bd']];
var key = ['item1', 'item2', 'item3'];
By using any javascript logic I want to get a new array in below format.
[
{item1: 'aa', item2: 'ab', item3: 'ac'},
{item1: 'bb', item2: 'bc', item3: 'bd'}
]
I tried using .forEach and .map() to achieve this, but somehow I couldn't able to do it.
Here is the sample code I tried.https://plnkr.co/edit/oKyjNsBu3wrRin7TaCIb?p=preview
var val = [['aa', 'ab', 'ac'], ['bb', 'bc', 'bd']];
var key = ['item1', 'item2', 'item3'];
var newArr = val.map((elm,i)=>{
return {[key[i]]: elm[i]}
})
console.log('newArr', newArr);
I need the output as below.
[
{item1: 'aa', item2: 'ab', item3: 'ac'},
{item1: 'bb', item2: 'bc', item3: 'bd'}
]
You can use .map() and .reduce() methods to get the desired output:
const vals = [['aa','ab','ac'],['bb','bc','bd']];
const keys = ['item1','item2','item3'];
const result = vals.map((val) => keys.reduce((r, c, i) => (r[c] = val[i], r), {}));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Map the val array (change its name to allVals for better clarity) to objects using Object.fromEntries:
var allVals = [['aa','ab','ac'],['bb','bc','bd']];
var keys = ['item1','item2','item3'];
const output = allVals.map(vals => Object.fromEntries(
vals.map((val, i) => [keys[i], val])
));
console.log(output);
Using Object.fromEntries():
const values = [['aa','ab','ac'],['bb','bc','bd']];
const keys = ['item1','item2','item3'];
const result = values.map(v => Object.fromEntries(keys.map((k, i) => [k, v[i]])));
console.log(result);

Two foreach replacement JS

Could you please recommend the more elegant way of handling these case?
const arr1 = [1, 2, 3];
const arr2 = ['a', 'b', 'c'];
const getCombinations = () => {
const combinations = [];
arr1.forEach(el1 => {
arr2.forEach(el2 => {
combinations.push({
el1,
el2
});
});
});
return combinations;
};
console.log(getCombinations());
You can use a Array.flatMap() with Array.map():
const arr1 = [1, 2, 3];
const arr2 = ['a', 'b', 'c'];
const getCombinations = (a, b) =>
a.flatMap(el1 => b.map(el2 => ({ el1, el2 })));
const result = getCombinations(arr1, arr2);
console.log(result);
You could take a slightly more dynamic aproach by taking the cartesian product first and then map the objects with the wanted properties.
const
cartesian = (a, b) => a.reduce((r, v) => r.concat(b.map(w => [].concat(v, w))), []),
takeKeys = keys => a => Object.assign(...a.map((v, i) => ({ [keys[i]]: v })))
array1 = [1, 2, 3],
array2 = ['a', 'b', 'c'],
result = [array1, array2]
.reduce(cartesian)
.map(takeKeys(['el1', 'el2']));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Categories

Resources