Combining object arrays ({a:a,b:b, c:c},{a:a,d:d,c:c}) to ({a:a,b:c,d:c})

僤鯓⒐⒋嵵緔 提交于 2019-12-08 13:35:37

问题


I have a list of data that I'm getting that I need to convert and "pivot" to turn one column into multiple columns.

The list of objects I have looks like this:

var list = [
{
    "date": "2016-05-31",
    "action": "test",
    "value": 10
},
{
    "date": "2016-05-31",
    "action": "run",
    "value": 8
},
{
    "date": "2016-06-01",
    "action": "delete",
    "value" : 2
},
{
    "date": "2016-06-01",
    "action": "test",
    "value": 5
},
]

I need to convert this for a charting library so that it looks like this:

var list = [
{
    "date": "2016-05-31",
    "test": 10,
    "run": 8,
    "delete": 0
},
{
    "date": "2016-06-01",
    "test": 5,
    "run": 0,
    "delete": 2
}
]

Is there a fairly easy way to do this using underscore.js functions like _.groupBy and _.map etc...?


回答1:


Here is an ES6 solution, which does not hard-code test, run or delete, but first retrieves all possible actions in the data:

function pivot(list) {
    var actions = list.reduce( (actions, o) => (actions[o.action] = 0, actions), {} );
    var res = list.reduce( (res, o) => ((res[o.date] = res[o.date] || Object.assign({ date: o.date }, actions))[o.action] += o.value, res), {});
    return Object.keys(res).map(key => res[key]);
}

// Sample data
var list = [{
    "date": "2016-05-31",
    "action": "test",
    "value": 10
}, {
    "date": "2016-05-31",
    "action": "run",
    "value": 8
}, {
    "date": "2016-06-01",
    "action": "delete",
    "value": 2
}, {
    "date": "2016-06-01",
    "action": "test",
    "value": 5
}];
// Call
var res = pivot(list);
// Output
console.log(res);

If an action value is repeated for the same date the corresponding values are added together (so numerical values are assumed).

Alternative focussing on speed

Following the comments on speed, I present here a function that does the job in one loop:

var list = [{
    "date": "2016-05-31",
    "action": "test",
    "value": 10
}, {
    "date": "2016-05-31",
    "action": "run",
    "value": 8
}, {
    "date": "2016-06-01",
    "action": "delete",
    "value": 2
}, {
    "date": "2016-06-01",
    "action": "test",
    "value": 5
}];

function pivot(list) {
    var res = {}, arr = [];
    for (var o of list)
        (res[o.date] || (arr[arr.push(res[o.date] = {
            date: o.date,
            test: 0,
            run : 0,
            "delete": 0
        })-1]))[o.action] += o.value;
    return arr;
}

var res = pivot(list);
console.log(res);

I have added this to the test suit Ismail RBOUH created.




回答2:


This iterates twice to create a map of the dates, then iterates again to insert the missing properties?

var list = [{
    "date": "2016-05-31",
    "action": "test",
    "value": 10
}, {
    "date": "2016-05-31",
    "action": "run",
    "value": 8
}, {
    "date": "2016-06-01",
    "action": "delete",
    "value": 2
}, {
    "date": "2016-06-01",
    "action": "test",
    "value": 5
}];

var map = {};

list.forEach(function(o) {
	if ( !(o.date in map) ) map[o.date] = {};
   	map[o.date][o.action] = o.value;
});

var sorted_list = Object.keys(map).map(function(k) {
	return {
    	"date"   : k,
    	"test"   : (map[k].test || 0),
        "run"    : (map[k].run || 0),
        "delete" : (map[k].delete || 0)
    }
});

document.body.innerHTML = '<pre>' + JSON.stringify(sorted_list, 0, 4) + '</pre>';



回答3:


Here's one way to do it, using .reduce() to create a temporary object to accumulate the values, and then .map() to create the final array:

var temp = list.reduce(function(c, v) {
  (c[v.date] || (c[v.date]={}))[v.action] = v.value;
  return c;
}, {});
var output = Object.keys(temp).map(function(k) {
  return {
    date : k,
    test : temp[k].test || 0,
    run : temp[k].run || 0,
    "delete" : temp[k].delete || 0
  }
});



回答4:


Here is an Underscore solution:

var result = _.chain(list).groupBy("date")
.mapObject(function(item, key) {    
    var d = {date: key};
    for(var i in item) d[item[i].action] = item[i].value;
    return d;
}).values().value();

var list = [{
    "date": "2016-05-31",
    "action": "test",
    "value": 10
}, {
    "date": "2016-05-31",
    "action": "run",
    "value": 8
}, {
    "date": "2016-06-01",
    "action": "delete",
    "value": 2
}, {
    "date": "2016-06-01",
    "action": "test",
    "value": 5
}, ];

var result = _.chain(list).groupBy("date")
.mapObject(function(item, key) {	
    var d = {date: key};
	for(var i in item) d[item[i].action] = item[i].value;
    return d;
}).values().value();

console.log(result);
<script src="
https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>


来源:https://stackoverflow.com/questions/38406333/combining-object-arrays-aa-bb-cc-aa-dd-cc-to-aa-bc-dc

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!