Reputation: 1471
I would like to transform the following array
[{
0-1s: 6,
1-2s: 2,
country: "us"
}, {
0-1s: 1,
1-2s: 4,
country: "ja"
}, {
0-1s: 3,
1-2s: 9,
country: "ca"
}]
Into an array like this:
[{
time: "0-1s",
us: 6,
ja: 1,
ca: 3
},{
time: "1-2s",
us: 2,
ja: 4,
ca: 9
}]
The idea is to pivot my array and make the country fields a new property and the time it took for each country a bucket so no matter how many countries, I only have 2 elements in my array (with as many countries as properties) This is just an example and I have 40+ countries. However, I haven't been able to figure out how can I achieve this new data structure in plan JavaScript.
How should I approach this?
Upvotes: 1
Views: 80
Reputation: 8740
You can try like this in a modular way (the concept of reusability).
I have used map() method defined on arrays to create new arrays.
Note: You can define keys to stop unnecessary iterations or if your array is huge and most of the keys are matched then no problem.
// function 1
function getNewArray(arr) {
let newArr = [];
if(arr.length) {
let keys = ["0-1s", "1-2s"];
newArr = keys.map((key) => {
let newObj = {}
// console.log(newObj, key)
for(let obj of arr) {
if(newObj["time"] === undefined) {
newObj["time"] = key
}
newObj[obj["country"]] =obj[key]
}
return newObj
})
}
return newArr
}
// function 2
function test() {
let arr = [{
"0-1s": 6,
"1-2s": 2,
country: "us"
}, {
"0-1s": 1,
"1-2s": 4,
country: "ja"
}, {
"0-1s": 3,
"1-2s": 9,
country: "ca"
}]
let newArr = getNewArray(arr)
console.log(newArr)
/*
[ { time: '0-1s', us: 6, ja: 1, ca: 3 },
{ time: '1-2s', us: 2, ja: 4, ca: 9 } ]
*/
/* --- Pretty printing --- */
console.log(JSON.stringify(newArr, null, 4))
/*
[
{
"time": "0-1s",
"us": 6,
"ja": 1,
"ca": 3
},
{
"time": "1-2s",
"us": 2,
"ja": 4,
"ca": 9
}
]
*/
}
// Start
test()
Upvotes: 0
Reputation: 35253
You could use reduce
to group them in to an accumulator object with "0-1s"
and "1-2s"
as keys. Then use Object.values()
to get the array of values:
const input = [{
"0-1s": 6,
"1-2s": 2,
country: "us"
}, {
"0-1s": 1,
"1-2s": 4,
country: "ja"
}, {
"0-1s": 3,
"1-2s": 9,
country: "ca"
}]
const grouped = input.reduce((r, o) => {
r["0-1s"] = r["0-1s"] || { time: "0-1s" };
r["1-2s"] = r["1-2s"] || { time: "1-2s" };
r["0-1s"][o.country] = o["0-1s"]
r["1-2s"][o.country] = o["1-2s"]
return r;
}, {})
console.log(Object.values(grouped))
If each object has more dynamic time ranges like 0-1s
etc, you could destrcuture the object in the reduce
parameter to get the country
and rest
of the time ranges to separate properties. Loop through the entries
of rest
to update value for each time
range:
const input = [{"0-1s":6,"1-2s":2,country:"us"},{"0-1s":1,"1-2s":4,country:"ja"},{"0-1s":3,"1-2s":9,country:"ca"}];
const grouped = input.reduce((r, { country, ...rest }) => {
Object.entries(rest).forEach(([time, v]) => {
r[time] = r[time] || { time };
r[time][country] = v
})
return r;
}, {})
console.log(Object.values(grouped))
Upvotes: 3
Reputation: 36584
Here is a little more dynamic code using reduce()
. First get array of unique keys i.e ['0-1s','1-2s']
then convert that to object. Then use reduce()
on the arr
and add the properties to it.
const arr = [{
'0-1s': 6,
'1-2s': 2,
country: "us"
}, {
'0-1s': 1,
'1-2s': 4,
country: "ja"
}, {
'0-1s': 3,
'1-2s': 9,
country: "ca"
}]
const obj = [...new Set(arr.map(x => Object.keys(x).filter(a => a.includes('-'))).flat())].reduce((ac,a) => (ac[a]=({time:a}),ac),{});
const res = arr.reduce((ac,a) => {
Object.keys(a).forEach(x => {
if(x.includes('-')) ac[x][a.country] = a[x];
})
return ac;
},obj)
console.log(Object.values(res))
Upvotes: 1