user3587624
user3587624

Reputation: 1471

Javascript: How to create an array with 'x' number of properties from another array?

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

Answers (3)

hygull
hygull

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

adiga
adiga

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

Maheer Ali
Maheer Ali

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

Related Questions