Transform a list of dictionaries into a dictionary of lists with Javascript

Viewed 2603

Is there a built-in Javascript function to transform a list of dictionaries:

const L = 
      [ { "day": "20201210", "count": "100" } 
      , { "day": "20201211", "count": "120" } 
      , { "day": "20201212", "count":  "90" } 
      , { "day": "20201213", "count": "150" } 
      ] 

into a dictionary of lists like this:

const D = 
      { "day"   : [ "20201210", "20201211", "20201212", "20201213"] 
      , "count" : [ "100", "120", "90", "150"] 
      } 

? If not what's the simplest way to do it in JS?

(It is a little-bit similar to matrix "transpose" operation).

Note: here it's a transpose and not a groupby like in Most efficient method to groupby on an array of objects

6 Answers

Assuming all objects have the same keys and your array is not empty, this will work:

let D = {};
Object.keys(L[0]).forEach(k => {
    D[k] = L.map(o => o[k]);
});

There are certainly more efficient solutions but this is short and concise and not too bad in terms of efficiency.

Here's a fairly short and efficient method for general values.

L.forEach(o => {
  Object.keys(o).forEach(k => {
    D[k] ||= [];
    D[k].push(o[k]);
  });
});

const L = [{
  "day": "20201210",
  "count": "100"
}, {
  "day": "20201211",
  "count": "120"
}, {
  "day": "20201212",
  "count": "90"
}, {
  "day": "20201213",
  "count": "150"
}]

let D = {};

L.forEach(o => {
  Object.keys(o).forEach(k => {
    D[k] ||= [];
    D[k].push(o[k]);
  });
});

console.log(D);

I don't think such a function exists, at least in vanilla JavaScript.

A simple, pure vanilla and clear to understand way of doing it would be like this:

var L = [
    {
        "day": "20201210",
        "count": "100"
    },
    {
        "day": "20201211",
        "count": "120"
    },
    {
        "day": "20201212",
        "count": "90"
    },
    {
        "day": "20201213",
        "count": "150"
    }
];
var D = { };

for (var dict in L)
{
    for (var key in L[dict]) 
    {
        if (D[key] == null) {
            D[key] = [ ];
        }
        
        D[key].push(L[dict][key]);
    }
} 

This is definitely not the most concise or most optimized way of doing it, though it will work.

You can just restructure your array of dictionaries as such, and re-map it with Array.prototype.map

E.g. (The following practice requires to iterate the elements with map N * X times where N is the length of L and X is the amount of properties you'd want to have in D, ignore this if you have many properties you'd want to watch.)

But, this is the easiest readable approach that I'd want to introduce to you before the 2nd approach.

const L = [{"day":"20201210","count":"100"},{"day":"20201211","count":"120"},{"day":"20201212","count":"90"},{"day":"20201213","count":"150"}];

const D = {
  'day': L.map(elem => elem['day']),
  'count': L.map(elem => elem['count']),
};

console.log(D);

Another approach I'd suggest is to use Array.prototype.reduce, this is by far favored in your case as it's easily expandable by adding more properties to the initial array.

const L = [{"day":"20201210","count":"100"},{"day":"20201211","count":"120"},{"day":"20201212","count":"90"},{"day":"20201213","count":"150"}];

const D = L.reduce((acc, cv) => {
  for (const propertyToGrab in acc) {
    if (cv.hasOwnProperty(propertyToGrab)) {
      acc[propertyToGrab].push(cv[propertyToGrab]);
    }
  }

   return acc;
}, {
  'day': [],
  'count': []
});

console.log(D);

const D={day:[], count:[]};

    for(const item of L){
    D.day.push(item.day);
    D.count.push(item.count);
    }
 const input = [{"day":"20201210","count":"100"},{"day":"20201211","count":"120"},{"day":"20201212","count":"90"},{"day":"20201213","count":"150"}];
 // Create a variable that will store the result
 let result = {};
 // Loop through the input with forEach
 input.forEach((element) => {
     // Loop through the keys 
    for(let key in element) {
        // Check if a key is not exist in the result 
        if(!result.hasOwnProperty(key)) {
            // Then create an key and assign an empty array to it
            result[key] = [];
        }
        // Push the elemnts to the array.
        result[key].push(element[key]);
    }
 });
Related