4

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

Basj
  • 41,386
  • 99
  • 383
  • 673
  • Does this answer your question? [Group by multiple values Underscore.JS but keep the keys and values](https://stackoverflow.com/questions/25550624/group-by-multiple-values-underscore-js-but-keep-the-keys-and-values) – AZ_ Dec 21 '20 at 11:50
  • using simple js [Most efficient method to groupby on an array of objects](https://stackoverflow.com/questions/14446511/most-efficient-method-to-groupby-on-an-array-of-objects) – AZ_ Dec 21 '20 at 11:52
  • 1
    This question should be reopened. This is not even related to grouping of array elements. The second linked question is related but this is still different enough to justify a new question. – lex82 Dec 21 '20 at 12:07
  • I changed my answer to work with an unknown list of keys – Mister Jojo Dec 21 '20 at 12:36
  • I changed my answer to make it a universal function, in the idea of your matrix function – Mister Jojo Dec 21 '20 at 12:45
  • 3) I changed my answer to make it a faster ( than any one else here) – Mister Jojo Dec 21 '20 at 16:05

6 Answers6

2

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.

lex82
  • 11,173
  • 2
  • 44
  • 69
2

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);
vrintle
  • 5,501
  • 2
  • 16
  • 46
  • 1
    `map()` produces new arrays that you don't need. It would be better to use `forEach()` since you are only interested in the side effects. – lex82 Dec 22 '20 at 21:09
1

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.

TARN4T1ON
  • 522
  • 2
  • 12
1

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);
choz
  • 17,242
  • 4
  • 53
  • 73
0
const D={day:[], count:[]};

    for(const item of L){
    D.day.push(item.day);
    D.count.push(item.count);
    }
miniman
  • 61
  • 3
0
 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]);
    }
 });
Karan Talwar
  • 108
  • 6