我有一大堆类似于此的数据:
var original = [
{ country : 'us', date : '2014-10-29', cost : 45.3 },
{ country : 'africa', date : '2014-10-29', cost : 60.5 },
{ country : 'south_america', date : '2014-10-30', cost : 10 },
{ country : 'us', date : '2014-10-30', cost : 30 }
];
我需要重新排列这些数据,使其看起来更像这样:
var newData = [
{ date : '2014-10-29', us : 45.3, africa : 60.5, south_america : 0 },
{ date : '2014-10-30', us : 30, africa : 0, south_america : 10 }
]
我是处理这样的数据集的新手,我很难找到任何有效的方法来解决这个问题......我唯一能想到的就是使用多个for循环,看起来很糟糕。有没有人有任何想法或建议?
答案 0 :(得分:2)
首先想到的是
var original = [
{ country : 'us', date : '2014-10-29', cost : 45.3 },
{ country : 'africa', date : '2014-10-29', cost : 60.5 },
{ country : 'south_america', date : '2014-10-30', cost : 10 },
{ country : 'us', date : '2014-10-30', cost : 30 }
];
var t = {};
var result = [];
original.forEach(function(entry) {
var n = t[entry.date] = t[entry.date] || {};
n.date = entry.date;
n[entry.country] = entry.cost;
});
for(var k in t) {
if (t.hasOwnProperty(k)) {
result.push(t[k]);
}
}
console.log(result);
没有临时对象可能有更好的方法,但你想要高效,我认为这是我能想到的最有效的方式
答案 1 :(得分:1)
不幸的是,看多个循环是解决这个问题的方法。你可以通过将它放在一个函数中然后将该函数隐藏在代码的底部来让自己对可怕的代码感觉更好。
Jaromanda的答案在内存和时间方面都更有效率,但是如果你真的有大量的数据,你应该考虑在服务器上重新组织它,因为输出数据比原来的要小。少转移。虽然您可能希望将工作量减轻到客户端。
如果您仍然认为重组数据客户端是可行的方法,您可能会喜欢这个功能,如果您更改属性名称,可以轻松使用此功能。
function groupAndMerge(original,groupBy,merge){
var grouped={},list=[];
original.forEach(function(o){
var k=o[groupBy];
if(!grouped[k]) grouped[ k ]=[];
grouped[k].push(o);
});
for(var i in grouped){
var d={};
list.push(d);
grouped[i].forEach(function(o){
d[groupBy]=i;
for(var k in merge) d[o[k]]=o[merge[k]];
});
}
return list;
}
var original = [
{ country : 'us', date : '2014-10-29', cost : 45.3 },
{ country : 'africa', date : '2014-10-29', cost : 60.5 },
{ country : 'south_america', date : '2014-10-30', cost : 10 },
{ country : 'us', date : '2014-10-30', cost : 30 }
];
var result=groupAndMerge(original,'date',{'country':'cost'});
答案 2 :(得分:1)
如果数据已经排序,则只使用一个循环的方法更快:
var output = document.querySelector('#output');
var original = [
{ country : 'us', date : '2014-10-29', cost : 45.3 },
{ country : 'africa', date : '2014-10-29', cost : 60.5 },
{ country : 'south_america', date : '2014-10-30', cost : 10 },
{ country : 'us', date : '2014-10-30', cost : 30 }
];
function mapData(data) {
var newData = [];
var newMap = {};
newMap.date = data[0].date;
for (var i = 0; i < data.length; i++) {
if (data[i].date === newMap.date) {
newMap[data[i].country] = data[i].cost;
}
else {
newData.push(newMap);
newMap = { date: data[i].date, [data[i].country]: data[i].cost };
}
}
newData.push(newMap);
return newData;
}
output.innerHTML = JSON.stringify(mapData(original));
<html>
<body>
<div id="output"></div>
</body>
</html>
这比Jaromanda的解决方案更快。但是,它又取决于已按排序顺序排列的数据。如果必须先对数据进行排序,则会很快落后:jsPerf。
然而,这两种解决方案都忽略了OP希望每个国家/地区都有每个日期的条目这一事实,即使特定日期的成本不存在(为零)。此要求还意味着必须使用多个循环并且会损害性能。
答案 3 :(得分:0)
您可以使用字典来存储指向与给定日期关联的条目的索引的指针,从而限制中间集合的创建。具有reduce函数的示例(在没有任何for循环的情况下离开)。
var original = [
{ country : 'us', date : '2014-10-29', cost : 45.3 },
{ country : 'africa', date : '2014-10-29', cost : 60.5 },
{ country : 'south_america', date : '2014-10-30', cost : 10 },
{ country : 'us', date : '2014-10-30', cost : 30 }
];
var newData = original.reduce(function(acc, d) {
var date = d.date;
var idx = acc.dict.indexOf(date);
var entry;
if (idx === -1) {
entry = { date: date };
acc.dict.push(date);
acc.list.push(entry);
} else {
entry = acc.list[idx];
}
entry[d.country] = d.cost;
return acc
}, {
list: [],
dict: []
}).list
document.querySelector('#result').innerHTML = JSON.stringify(newData)
&#13;
<div id='result'></div>
&#13;
您可以使代码更具可重用性,但这会产生轻微的性能成本。
var original = [
{ country : 'us', date : '2014-10-29', cost : 45.3 },
{ country : 'africa', date : '2014-10-29', cost : 60.5 },
{ country : 'south_america', date : '2014-10-30', cost : 10 },
{ country : 'us', date : '2014-10-30', cost : 30 }
];
var groupByDateAndAggregateCostByCountry = {
getGroup : function(d) { return {k: 'date', v: d.date}; },
assignData: function(d) { return {[d.country]: d.cost}; }
}
var newData = original.reduce(function(acc, d) {
var gp = acc.fn.getGroup(d);
var idx = acc.dict.indexOf(gp.v);
var entry;
if(idx === -1) {
entry = {[gp.k] : gp.v};
acc.dict.push(gp.v);
acc.list.push(entry);
} else {
entry = acc.list[idx];
}
Object.assign(entry, acc.fn.assignData(d));
return acc;
}, {list: [], dict: [], fn: groupByDateAndAggregateCostByCountry}).list;
newData.map(function(d) {console.log(d)});
document.querySelector("#result2").innerHTML = JSON.stringify(newData);
&#13;
<div id="result2"></div>
&#13;