按对象分组多个字段

时间:2016-02-19 13:24:49

标签: javascript

我正在尝试确定最佳数据类型,以将对象数组排序到属性定义的组中。我有一个对象数组,如下所示:

var people = [
    {
        name: 'Pete',
        gender: 'Male',
        age: 22

    },
    {
        name: 'Samantha',
        gender: 'Female',
        age: 20

    },
    {
        name: 'Frank',
        gender: 'Male',
        age: 22

    },
    {
        name: 'Gary',
        gender: 'Male',
        age: 21

    },
    {
        name: 'Maria',
        gender: 'Female',
        age: 20

    },
    {
        name: 'Hannah',
        gender: 'Female',
        age: 21

    },
    {
        name: 'Pete',
        gender: 'Male',
        age: 20

    }
];

我需要将这些对象分组到任意定义的组中。 E.g:

  1. 第1组:gender
  2. 第2组:age
  3. (这可以由服务器定义,如果我们愿意,可以更改为包含第三组。)

    然后给我(视觉上):

    Male:
       21:
         Gary
       22:
         Pete
         Frank
    
    Female
       20:
         Samantha
         Maria
       21:
         Hannah
    

    认为适当的数据类型将是对象的对象。即:

    {
        Male: {
            21: {
                [
                    {
                        name: 'Gary',
                        gender: 'Male',
                        age: 21
    
                    }
                ]
            },
            22: {
                [
                    {
                        name: 'Pete',
                        gender: 'Male',
                        age: 22
    
                    },
                    {
                        name: 'Frank',
                        gender: 'Male',
                        age: 22
    
                    }
                ]
            }
        },
        Female: {
            20: {
                [
                    {
                        name: 'Samantha',
                        gender: 'Female',
                        age: 20
    
                    },
                    {
                        name: 'Maria',
                        gender: 'Female',
                        age: 20
    
                    }
                ]
            },
            21: {
                [
                    {
                        name: 'Hannah',
                        gender: 'Female',
                        age: 21
    
                    }
                ]
            }
        }
    }
    

    但是,对于我的生活,我无法解决这些问题,将这些对象分类为代表上述数据的数据类型。

    underscore.js中有一个名为_.groupBy(arr, callback)的实用工具,我可以按如下方式使用:

    _.groupBy(people, function (person) {
        var props = ['gender', 'age'], // server-defined
            prop = [];
    
        for (var i = 0, length = props.length; i < length; i++) {
            prop.push(person[props[i]]);
        }
    
        return prop.join('|');
    });
    

    这给了我一个1深度的对象,我可以使用for...in循环遍历键,然后循环构建上面的对象,但这是我坚持的代码。

    返回的对象是:

    {
        "Male|22": [
            {
                "name": "Pete",
                "gender": "Male",
                "age": 22
            },
            {
                "name": "Frank",
                "gender": "Male",
                "age": 22
            }
        ],
        "Female|20": [
            {
                "name": "Samantha",
                "gender": "Female",
                "age": 20
            },
            {
                "name": "Maria",
                "gender": "Female",
                "age": 20
            }
        ],
        "Male|21": [
            {
                "name": "Gary",
                "gender": "Male",
                "age": 21
            }
        ],
        "Female|21": [
            {
                "name": "Hannah",
                "gender": "Female",
                "age": 21
            }
        ],
        "Male|20": [
            {
                "name": "Pete",
                "gender": "Male",
                "age": 20
            }
        ]
    }
    

    我正在考虑循环遍历对象中的每个键,在管道(|)处拆分并使用递归来构造包含数据组/数组的对象的新对象。

    这是实现这一目标的可怕方式,但我不知道如何做到这一点。

    我错过了更好的方法吗?

4 个答案:

答案 0 :(得分:2)

也许这会对你有所帮助。它使用具有对象属性的数组,结果按属性的内容进行分组。

forEach循环遍历数据。 reduce循环用于为每个给定组生成分组属性,如果它是最后一个,则返回一个数组(如果尚未存在)。

最后一步是将其中一个人的值推送到数组。

&#13;
&#13;
var people = [{ name: 'Pete', gender: 'Male', age: 22 }, { name: 'Samantha', gender: 'Female', age: 20 }, { name: 'Frank', gender: 'Male', age: 22 }, { name: 'Gary', gender: 'Male', age: 21 }, { name: 'Maria', gender: 'Female', age: 20 }, { name: 'Hannah', gender: 'Female', age: 21 }, { name: 'Pete', gender: 'Male', age: 20 }],
    groups = ['gender', 'age'],
    grouped = {};

people.forEach(function (a) {
    groups.reduce(function (o, g, i) {                            // take existing object,
        o[a[g]] = o[a[g]] || (i + 1 === groups.length ? [] : {}); // or generate new obj, or
        return o[a[g]];                                           // at last, then an array
    }, grouped).push(a);
});

document.write('<pre>' + JSON.stringify(grouped, 0, 4) + '</pre>');
&#13;
&#13;
&#13;

答案 1 :(得分:1)

我不同意你的预期输出。我认为你应该只有一个具有MaleFemale数组属性的对象,并使用此代码填充数组:

var obj = people.reduce(function (p, c, i) {
  p[c.gender].push(c); 
  return p;
}, { Male: [], Female: [] });

如果您想过滤那些数组,可以编写如下函数:

function getMaleByAge(obj, age) {
  return obj.Male.filter(function (el) {
    return el.age === age;
  })
}

getMaleByAge(obj, 21); // { name: "Gary", gender: "Male", age: 21 }

DEMO

答案 2 :(得分:1)

使用_.groupBy&amp; _.map

var output _.map(_.groupBy(people,'gender'),function(obj,key){
  var temp = {};
temp[key] = _.groupBy(obj,'age')
  return  temp;
});

console.log(JSON.stringify(output,null,' '))

将提供以下输出

 [{
  "Male": {
   "20": [
    {
     "name": "Pete",
     "gender": "Male",
     "age": 20
    }
   ],
   "21": [
    {
     "name": "Gary",
     "gender": "Male",
     "age": 21
    }
   ],
   "22": [
    {
     "name": "Pete",
     "gender": "Male",
     "age": 22
    },
    {
     "name": "Frank",
     "gender": "Male",
     "age": 22
    }
   ]
  }
 },
 {
  "Female": {
   "20": [
    {
     "name": "Samantha",
     "gender": "Female",
     "age": 20
    },
    {
     "name": "Maria",
     "gender": "Female",
     "age": 20
    }
   ],
   "21": [
    {
     "name": "Hannah",
     "gender": "Female",
     "age": 21
    }
   ]
  }
 }
]

答案 3 :(得分:0)

我真的不明白为什么人们总是使用框架来做这类事情。 香草是faster,这不是很难编码......

&#13;
&#13;
var people = [    { name: 'Pete', gender: 'Male', age: 22 },     { name: 'Samantha', gender: 'Female', age: 20 },     { name: 'Frank', gender: 'Male', age: 22 },     { name: 'Gary', gender: 'Male', age: 21 },     { name: 'Maria', gender: 'Female', age: 20 },     { name: 'Hannah', gender: 'Female', age: 21 }, { name: 'Pete', gender: 'Male', age: 20 }];


var grouped = {}; // final object 
for (var i=0,len=people.length,p;i<len;i++) { // faster than .forEach
  p = people[i];

  if (grouped[p.gender] === undefined) // twice faster then hasOwnProperty
    grouped[p.gender] = {};

  if (grouped[p.gender][p.age] === undefined)
    grouped[p.gender][p.age] = [];

  grouped[p.gender][p.age].push(p); // your groupby is HERE xD
}
document.getElementById('grouped').innerHTML = JSON.stringify(grouped, null, 2)
&#13;
<pre id="grouped"></pre>
&#13;
&#13;
&#13;