从对象数组创建新对象,并按特定匹配键/值进行分组

时间:2017-03-07 22:27:14

标签: javascript

我正在处理的对象数据示例

var myData = [{
  "name": "John",
  "age": 30,
  "interest": "Baseball"
},
{
  "name": "Bob",
  "age": 21,
  "interest": "Baseball"
},
{
  "name" : "Sally",
  "age" : 29,
  "interest": "Tennis"
}]

我正在试图找出按兴趣分组的最简单方法。我愿意使用lodash或下划线,但我无法将最终结果看作这样......

我希望这是输出:

[{ "Baseball" : [{
                  "name": "John",
                  "age" : 30
                 },
                 {
                  "name" : "Bob",
                  "age" : 21
                 }]
 },
 { "Tennis" : [{
                 "name" : "Sally",
                 "age" : 21
               }]
 }];

基本上,每个兴趣都成为一个新的对象键,包含数组中的所有匹配值。

我在构建此输出时遇到问题。任何帮助将不胜感激。我更喜欢使用lodash / underscore来保持容易。

谢谢!

4 个答案:

答案 0 :(得分:2)

分组操作可以通过匹配字典中的值(哈希表)来完成。在JavaScript中,所有对象都是以属性名作为键的字典,对于我们使用数组的值。

例如(按下"运行代码段"按钮,查看结果):



function groupBy( input, propertyName ) {
    
    var output = {};
    for(var i = 0; i < input.length; i++) {
        
        var groupByValue = input[i][propertyName];
        if( !(groupByValue in output) ) {
            output[ groupByValue ] = [];
        }

        var dolly = cloneObjectButIgnoreProperty( input[i], propertyName );
        output[ groupByValue ].push( dolly );
    }

    return output;
}

function cloneObjectButIgnoreProperty( value, ignorePropertyName ) {
    
    var dolly = {};
    var propertyNames = Object.keys( value );
    for( var i = 0; i < propertyNames .length; i++ ) {
        var propertyName = propertyNames[i];
        if( propertyName == ignorePropertyName ) continue;
        dolly[propertyName ] = value[propertyName ];
    }
    return dolly;
}

var myData = [
    {
        "name": "John",
        "age": 30,
        "interest": "Baseball"
    },
    {
        "name": "Bob",
        "age": 21,
        "interest": "Baseball"
    },
    {
        "name" : "Sally",
        "age" : 29,
        "interest": "Tennis"
    }
];

var groupedByInterest = groupBy( myData, 'interest' );
console.log( "By interest:" );
console.log( groupedByInterest );

var groupedByName = groupBy( myData, 'name' );
console.log( "By name:" );
console.log( groupedByName );

var groupedByAge = groupBy( myData, 'age' );
console.log( "By age:" );
console.log( groupedByAge  );
&#13;
&#13;
&#13;

答案 1 :(得分:2)

您可以使用Array.reduce

&#13;
&#13;
var myData = [
{
  "name": "John",
  "age": 30,
  "interest": "Baseball"
},
{
  "name": "Bob",
  "age": 21,
  "interest": "Baseball"
},
{
  "name" : "Sally",
  "age" : 29,
  "interest": "Tennis"
}];

var result = myData.reduce(function(entities, obj) {
   entities[obj.interest] = (entities[obj.interest] || []).concat({
      name: obj.name,
      age: obj.age
   });
   return entities;
}, {});
console.log(result);
&#13;
&#13;
&#13;

更一般的方法:

&#13;
&#13;
function groupBy(data, key, tFunc) {
   mapFunc = (typeof tFunc === "function")? tFunc: function(o) { return o };
   return (Array.isArray(data)?data:[]).reduce(function(entities, o) {
     if(o[key]) {
       entities[o[key]] = (entities[o[key]] || []).concat(tFunc(o));
     }
     return entities;
   }, {});
}


// test code
var myData = [
{
  "name": "John",
  "age": 30,
  "interest": "Baseball"
},
{
  "name": "Bob",
  "age": 21,
  "interest": "Baseball"
},
{
  "name" : "Sally",
  "age" : 29,
  "interest": "Tennis"
}];

var result = groupBy(myData, "interest", function(o) { return { name: o.name, age: o.age}});
console.log(result);
var result2 = groupBy(myData, "age", function(o) { return o.name});
console.log(result2);
&#13;
&#13;
&#13;

答案 2 :(得分:0)

使用Array.prototype.reduce()函数的解决方案:

&#13;
&#13;
var myData = [{ "name": "John", "age": 30, "interest": "Baseball" }, { "name": "Bob", "age": 21,     "interest": "Baseball" }, { "name" : "Sally", "age" : 29, "interest": "Tennis" }],

    result = myData.reduce(function (r, o) {
        r[o.interest] = r[o.interest] || [];
        r[o.interest].push({name: o.name, age: o.age});
        return r;
    }, {});

console.log(result);
&#13;
&#13;
&#13;

答案 3 :(得分:0)

&#13;
&#13;
var myData = [{name:"John",age:30,interest:"Baseball"},{name:"Bob",age:21,interest:"Baseball"},{name:"Sally",age:29,interest:"Tennis"}],
    result = [],
    interests = [...new Set(myData.map(v => v.interest))];
    
    interests.forEach(v => result.push({ [v] : [] }));
    myData.forEach((v,i) => result.forEach((c,i) => Object.keys(c)[0] == v.interest ? result[i][v.interest].push({name: v.name, age: v.age}) : c))
    console.log(result);
&#13;
&#13;
&#13;