从服务中我收到一个带键值对的JSON对象,我需要从它们动态创建对象,按一列分组。
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" }
]
我需要将其转换为以下对象数组:
[
{ Group : "A", Name : "John", Age : 30, City : "London" },
{ Group : "B", Name : "Hans", Age : 35, City : "Berlin" },
{ Group : "C", Name : "José", Age : 25, City : "Madrid" }
]
每个组都可以包含任意数量的键值对。
目前我有一个可行的解决方案,但我不知道它是否是最佳的:
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]);
}
}
您可以在此处查看小提琴:http://jsbin.com/ozizom/1/
你有更好的解决方案吗?
答案 0 :(得分:5)
假设JSON记录总是按组排序,这是另一种方法:
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是一个有效的例子。
答案 1 :(得分:3)
这是一个解决方案,通过使用JavaScript惯用法减少代码大小(无论好坏:-)。此解决方案不依赖于输入值的顺序:
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]; });
一个工作示例位于http://jsfiddle.net/arQww。
这是我能找到的最快的解决方案,它假定值始终按组排序:
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);
}
效果比较为http://jsperf.com/vnmzc。虽然第二种解决方案更快,但两者的性能都是O(n),它们之间的实际差异将是无关紧要的,因此第一种解决方案可能更为可取,因为它更简单,更通用。
答案 2 :(得分:1)
如果你必须经常操作数据,我会推荐underscore框架。 这就是解决方案的内容:
/*
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')))
})
答案 3 :(得分:-1)
我需要一个类似问题的帮助,买我想要总结价值。我有这个带对象的数组
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"}
];
我希望用户从选项菜单中选择要汇总的月份。
因此,如果用户从选择菜单中选择August 2014
,我想根据ValueOneToSum
对所有ValueTwoToSum
值和Aug2014
值求和,我该怎么做? ?
例如:totalSumOne
的{{1}}为Aug2014
,168
为totalSumTwo
。