2016-02-19 92 views
1

我正在尝试确定最佳数据类型以将对象数组排序为属性定义的组。我有一个对象阵列,如下所示:按对象分组的多个字段

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 

    } 
]; 

我需要将这些对象分组到任意定义的组中。例如:

  1. 组1:gender
  2. 组2:age

(这可以由服务器来定义,并且可以改变以包含第三组,如果我们希望。)

然后给我(视觉):

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('|'); 
}); 

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

返回的对象是:

{ 
    "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 
     } 
    ] 
} 

我想的那么通过在管道(|)对象中的每个关键,分裂循环和使用递归构建包含对象的新对象组/数据数组。

这是实现这个可怕的方式,但我不知道如何去做,否则。

有没有更好的方法我错过了?

回答

2

也许这可以帮助你。它利用具有对象属性的数组,并将结果按属性的内容分组。

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

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

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>');

+0

这个工程!分组允许任意长度。 :)你能详细描述一下吗? – keldar

+0

我有类似的东西 - 但它非常冗长,想要更简洁的东西:) - 这太棒了! – keldar

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

+0

由于@andy - 唯一的问题是,该对象可以* *含有多种性质(I使用本实施例以简化的情况)和基团可以是任意水平。因此,每个“人物”对象都可以包含20个属性,我们可能需要将这些属性组织为5个组。合理? – keldar

+1

然后只需按照您认为合适的原始数据进行过滤。只是女人? 'people.filter(function(el){return el.gender ==='Female';});'不是重新整理整个数据集,而是选择需要使用的数据组。 – Andy

+1

即使是21岁的女性:'people.filter(function(el){return el.gender ==='Female'&& el.age === 21;});'。简单。我认为你为自己按计划的方式做了很多工作。希望它能解决不管:) – Andy

1

使用_.groupBy & _.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 
    } 
    ] 
    } 
} 
] 
+0

这看起来非常令人兴奋 - 我现在要实现这个(给我五个),因为我有很多测试数据可以尝试。 – keldar

+0

这可以用于任意长度的分组属性(即如果我有3个属性而不是2)? – keldar

+0

考虑到这一点,我可以使用递归......现在玩一个游戏。 – keldar

0

我真的不明白为什么人们总是用框架之类的东西。 香草是faster,这是不是太难代码...

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)
<pre id="grouped"></pre>