我有一个JSON如下。
var test = [{
"id": "3",
"city": "seattle",
"place" : "xxx",
"usage" : "163612",
"available": "162500"
}, {
"id": "4",
"city": "washington",
"place" : "xxx",
"usage" : "52542",
"available": "86624"
}, {
"id": "3",
"city": "seattle",
"place" : "yyy",
"usage" : "163612",
"available": "962500"
},
{
"id": "5",
"city": "seattle",
"place" : "yyy",
"usage" : "562",
"available": "24252"
},
{
"id": "4",
"city": "washington",
"place" : "yyy",
"usage" : "163612",
"available": "319250"
}]
我想通过'id'和'city'将这个JSON分组。新形成的分组JSON应如下所示。
[
{
"3": {
"seattle": [
{
"xxx": {
"usage": "163612",
"available": "162500"
}
},
{
"yyy": {
"usage": "163612",
"available": "962500"
}
}
]
}
},
{
"4": {
"washington": [
{
"xxx": {
"usage": "52542",
"available": "86624"
}
},
{
"yyy": {
"usage": "163612",
"available": "319250"
}
}
]
}
},
{
"5": {
"seattle": [
{
"xxx": {
"usage": "562",
"available": "24252"
}
}
]
}
}
]
我尝试了循环和排序,但我无法获得所需的结果。有没有办法构建这个JSON。
答案 0 :(得分:2)
以下是通过多个字段进行分组的一种方法:
http://jsbin.com/xixemo/edit?js,console
(function () {
"use strict";
var test = [{
"id": "3",
"city": "seattle",
"place" : "xxx",
"usage" : "163612",
"available": "162500"
}, {
"id": "4",
"city": "washington",
"place" : "xxx",
"usage" : "52542",
"available": "86624"
}, {
"id": "3",
"city": "seattle",
"place" : "yyy",
"usage" : "163612",
"available": "962500"
},
{
"id": "5",
"city": "seattle",
"place" : "yyy",
"usage" : "562",
"available": "24252"
},
{
"id": "4",
"city": "washington",
"place" : "yyy",
"usage" : "163612",
"available": "319250"
}],
getRemainingProperties = function (obj, propertiesToExclude) {
return Object.keys(obj)
.filter(function (key) {
return !propertiesToExclude.includes(key);
})
.reduce(function (acc, curr) {
var result = {};
if (!acc) {
result[curr] = obj[curr];
return result;
}
result = acc;
result[curr] = obj[curr];
return result;
}, undefined);
},
excludedProperties = ["id", "city", "place"],
transformCity = function (cityInformation) {
var id = {},
city = {},
place = {},
remainder = getRemainingProperties(cityInformation, excludedProperties);
place[cityInformation.place] = remainder;
city[cityInformation.city] = [place];
id[cityInformation.id] = city;
return id;
},
initialReduceUndefinedValue,
idExists = function (searchArray, id) {
return searchArray.reduce(function (acc, curr) {
if (!acc){
return curr.hasOwnProperty(id);
}
return true;
}, undefined);
},
lift = function (array) {
//returns an object from inside container array without using array index
if (!Array.isArray(array)) {
return array;
}
return array.reduce(function (acc, curr) {
return curr;
});
},
answer = test.reduce(function (acc, curr) {
var result,
matchingId, //create a new object that will have appended properties for the current city
missingPlace = {};
if (!acc) {
return [transformCity(curr)];
}
if (idExists(acc, curr.id)) {
result = acc.filter(function (obj) {
//store the unmodified objects to return
return !obj.hasOwnProperty(curr.id);
});
matchingId = lift(acc.filter(function (obj) {
return obj.hasOwnProperty(curr.id);
}));
if (!matchingId[curr.id].hasOwnProperty(curr.city)) {
//if the object does not have the city, then add the city
matchingId[curr.city] = {};
}
if (!matchingId[curr.id][curr.city].hasOwnProperty(curr.place)) {
//if the object does not have the place, then add the place
missingPlace[curr.place] = getRemainingProperties(curr, excludedProperties);
matchingId[curr.id][curr.city].push(missingPlace);
}
result.push(matchingId);//add here just incase a city is duplicated
return result;
} else {//unique city id found, add new city
acc.push(transformCity(curr));
}
return acc;
}, initialReduceUndefinedValue);
console.log(answer);
}());
我已经概括了其余属性的包含,因此不必明确定义它们(根据评论中OP的要求)。
我试图避免使用for循环,以便从解决方案中提取迭代细节。我还采用了函数式编程方法,并试图避免创建带副作用的函数。在加载到jsbin的解决方案中,我添加了一个用于数组包含的polyfill,它有望进入ECMAScript版本7(预计在2016年)。在Javascript中有一个有用的"功能编程"可能有帮助的教程:
http://jhusain.github.io/learnrx/
此答案的可能扩展是对分组数据进行排序,以匹配OP列出的示例输出。
答案 1 :(得分:1)
我不知道这是不是你想要的。
var newObj = [];
for (var i in test) {
var cityObj = test[i];
var newItem = {};
var foundItem = false;
for (var j in newObj) {
var existingItem = newObj[j];
if (newObj[j].hasOwnProperty(cityObj.id)) {
foundItem = j;
}
}
if (!foundItem) {
newItem[cityObj.id] = {};
newItem[cityObj.id][cityObj.city] = {};
newItem[cityObj.id][cityObj.city][cityObj.place] = { usage: cityObj.usage, available: cityObj.available };
newObj.push(newItem);
} else {
newObj[foundItem][cityObj.id][cityObj.city][cityObj.place] = { usage: cityObj.usage, available: cityObj.available };
}
}
console.dir(newObj);
如果有帮助,请告诉我。
已更改以符合您的说明:
var newObj = [];
for (var i in test) {
var cityObj = test[i];
var newItem = {};
var foundItem = false;
for (var j in newObj) {
var existingItem = newObj[j];
if (newObj[j].hasOwnProperty(cityObj.id)) {
foundItem = j;
}
}
if (!foundItem) {
newItem[cityObj.id] = {};
newItem[cityObj.id][cityObj.city] = [];
var place = {};
place[cityObj.place] = { usage: cityObj.usage, available: cityObj.available };
newItem[cityObj.id][cityObj.city].push(place);
newObj.push(newItem);
} else {
var place = {};
place[cityObj.place] = { usage: cityObj.usage, available: cityObj.available };
newObj[foundItem][cityObj.id][cityObj.city].push(place);
}
}
console.dir(newObj);
答案 2 :(得分:0)
我认为这将是一个更好的解决方案:
function group(data, column) {
var generatedData = {};
for (var i in data){
var dt = data[i];
var key = dt[column];
if (!(key in generatedData)) {
generatedData[key] = [];
}
generatedData[key].push(dt);
}
return generatedData;
}