Creating an array of objects from key-value pairs

From the service, I get a JSON object with key-value pairs, and I need to dynamically create objects from them, grouped by one column.

JSON is as follows:

[ { "Group" : "A", "Key" : "Name", "Value" : "John" }, { "Group" : "A", "Key" : "Age", "Value" : "30" }, { "Group" : "A", "Key" : "City", "Value" : "London" }, { "Group" : "B", "Key" : "Name", "Value" : "Hans" }, { "Group" : "B", "Key" : "Age", "Value" : "35" }, { "Group" : "B", "Key" : "City", "Value" : "Berlin" }, { "Group" : "C", "Key" : "Name", "Value" : "José" }, { "Group" : "C", "Key" : "Age", "Value" : "25" }, { "Group" : "C", "Key" : "City", "Value" : "Madrid" } ] 

I would need to convert it to the following array of objects:

 [ { Group : "A", Name : "John", Age : 30, City : "London" }, { Group : "B", Name : "Hans", Age : 35, City : "Berlin" }, { Group : "C", Name : "José", Age : 25, City : "Madrid" } ] 

Each group can contain any number of key-value pairs.

I currently have a working solution for this, but I don't know if this is optimal:

 var items = [ { "Group" : "A", "Key" : "Name", "Value" : "John" }, { "Group" : "A", "Key" : "Age", "Value" : "30" }, { "Group" : "A", "Key" : "City", "Value" : "London" }, { "Group" : "B", "Key" : "Name", "Value" : "Hans" }, { "Group" : "B", "Key" : "Age", "Value" : "35" }, { "Group" : "B", "Key" : "City", "Value" : "Berlin" }, { "Group" : "C", "Key" : "Name", "Value" : "José" }, { "Group" : "C", "Key" : "Age", "Value" : "25" }, { "Group" : "C", "Key" : "City", "Value" : "Madrid" } ], item, record, hash = {}, results = []; // Create a "hash" object to build up for (var i = 0, len = items.length; i < len; i += 1) { item = items[i]; if (!hash[item.Group]) { hash[item.Group] = { Group : item.Group }; } hash[item.Group][item.Key] = item.Value; } // Push each item in the hash to the array for (record in hash) { if(hash.hasOwnProperty(record)) { results.push(hash[record]); } } 

You can check the script here: http://jsbin.com/ozizom/1/

Do you have a better solution for this?

+4
source share
4 answers

Assuming JSON entries will always be sorted by Group, here is another approach:

 var json = [ { "Group" : "A", "Key" : "Name", "Value" : "John" }, { "Group" : "A", "Key" : "Age", "Value" : "30" }, { "Group" : "A", "Key" : "City", "Value" : "London" }, { "Group" : "B", "Key" : "Name", "Value" : "Hans" }, { "Group" : "B", "Key" : "Age", "Value" : "35" }, { "Group" : "B", "Key" : "City", "Value" : "Berlin" }, { "Group" : "C", "Key" : "Name", "Value" : "José" }, { "Group" : "C", "Key" : "Age", "Value" : "25" }, { "Group" : "C", "Key" : "City", "Value" : "Madrid" } ]; var array = []; var previousGroup = null; for(var i=0; i<json.length; i++) { var group = json[i].Group; if(previousGroup != group) { array.push({Group: group}); previousGroup = group; } array[array.length-1][json[i].Key] = json[i].Value; } 

Here is a working example.

+5
source

Here's a solution where code size decreases (better or worse :-) using JavaScript idioms. This solution is independent of the order of input values:

 var values = [ {Group: 'A', Key: 'Name', Value: 'John'}, {Group: 'A', Key: 'Age', Value: '30'}, {Group: 'A', Key: 'City', Value: 'London'}, {Group: 'B', Key: 'Name', Value: 'Hans'}, {Group: 'B', Key: 'Age', Value: '35'}, {Group: 'B', Key: 'City', Value: 'Berlin'}, {Group: 'C', Key: 'Name', Value: 'José'}, {Group: 'C', Key: 'Age', Value: '25'}, {Group: 'C', Key: 'City', Value: 'Madrid'} ]; var map = {}; values.forEach(function(value) { map[value.Group] = map[value.Group] || {Group: value.Group}; map[value.Group][value.Key] = value.Value; }); var results = Object.keys(map).map(function(key) { return map[key]; }); 

Working example: http://jsfiddle.net/arQww .

Here's the quickest solution you can find, which assumes that the values ​​will always be sorted by Group:

 var group, results = []; for (var i = 0; i < values.length; ) { results.push({Group: group = values[i].Group}); do { results.push[results.length - 1][values[i].Key] = values[i].Value; } while (++i < values.length && values[i].Group == group); } 

Performance Comparison - http://jsperf.com/vnmzc . While this second solution is faster, the performance of both O (n) and the real difference between them will not be significant, so the first solution is probably preferable because it is simpler and more general.

+3
source

If you have to manipulate a lot of data, I would recommend the underscore framework. Here's what the solution will look like:

 /* We group items into object that looks like {group: attributes, ..} Then for each group we create result object denoting group, and extend result with object created from keys and values of attributes */ _.map(_.groupBy(items, function (item) {return item.Group}), function (attributes, group) { return _.extend({Group: group}, _.object(_.pluck(attributes, 'Key'), _.pluck(attributes, 'Value'))) }) 
+1
source

I need help with a similar problem, buy, I want to summarize the values. I have this array with objects

 var myArrWithObj = [ {DateToSort: "Jul2014", ValueOneToSum: "60", ValueTwoToSum: "15"}, {DateToSort: "Jul2014", ValueOneToSum: "30", ValueTwoToSum: "50"}, {DateToSort: "Jul2014", ValueOneToSum: "12", ValueTwoToSum: "22"}, {DateToSort: "Aug2014", ValueOneToSum: "65", ValueTwoToSum: "25"}, {DateToSort: "Aug2014", ValueOneToSum: "13", ValueTwoToSum: "10"}, {DateToSort: "Aug2014", ValueOneToSum: "90", ValueTwoToSum: "20"}, {DateToSort: "Sep2014", ValueOneToSum: "60", ValueTwoToSum: "15"}, {DateToSort: "Sep2014", ValueOneToSum: "60", ValueTwoToSum: "18"}, {DateToSort: "Sep2014", ValueOneToSum: "75", ValueTwoToSum: "18"} ]; 

and I want the user to choose which month to sum from the options menu.

So, if the user selects August 2014 in the selection menu, I want to sum all the values ​​of ValueOneToSum and ValueTwoToSum based on Aug2014 , how can I do this?

For example: totalSumOne for Aug2014 will be 168 and totalSumTwo will be 55 .

-1
source

Source: https://habr.com/ru/post/1432640/


All Articles