我有一个对象。它看起来如下:
[
{
"name":"Display",
"group":"Technical detals",
"id":"60",
"value":"4"
},
{
"name":"Manufacturer",
"group":"Manufacturer",
"id":"58",
"value":"Apple"
},
{
"name":"OS",
"group":"Technical detals",
"id":"37",
"value":"Apple iOS"
}
]
我想按组字段对这些数据进行分组并获取此对象:
var obj = {
0 = [
{
'group' = 'Technical detals',
'name' = 'Display',
'id' = '60',
'value' = '4'
},
{
'group' = 'Technical detals',
'name' = 'OS',
'id' = '37',
'value' = 'Apple iOS'
}],
1 = [
{
'group' = 'Manufacturer',
'name' = 'Manufacturer',
'id' = '58',
'value' = 'Apple'
}]
}
如何分组我的第一个对象?
答案 0 :(得分:14)
尝试这样的事情:
function groupBy(collection, property) {
var i = 0, val, index,
values = [], result = [];
for (; i < collection.length; i++) {
val = collection[i][property];
index = values.indexOf(val);
if (index > -1)
result[index].push(collection[i]);
else {
values.push(val);
result.push([collection[i]]);
}
}
return result;
}
var obj = groupBy(list, "group");
请注意,Array.prototype.indexOf
未在IE8及更早版本中定义,但有常见的polyfill。
答案 1 :(得分:8)
如果您在应用程序中使用underscore.js,则只需执行以下操作:
var groups = _.groupBy(data, 'group'); // data is your initial collection
或者如果您不想使用任何库,那么您可以自己完成:
var groups = { };
data.forEach(function(item){
var list = groups[item.group];
if(list){
list.push(item);
} else{
groups[item.group] = [item];
}
});
中看到这两个示例
答案 2 :(得分:6)
您可以为组使用哈希表,并使用Array#forEach
来迭代数组。
然后检查哈希是否存在,如果没有为它分配一个空数组并将其推送到结果集。
稍后将实际元素推送到哈希数组。
angular.module('Submenu', []).directive('Menu', [
function() {
var detectSubmenuPostion, linkFunction;
detectSubmenuPostion = function() {
var $button, $ul, spaceDown, spaceUp, ulOffset;
$ul = angular.element('.submenu-item');
$button = angular.element('.submenu-icon');
ulOffset = $ul.offset();
spaceUp = ulOffset.top - $button.height() - $ul.height() - $(window).scrollTop();
spaceDown = $(window).scrollTop() + $(window).height() - (ulOffset.top + $ul.height());
if (spaceDown < 0 && (spaceUp >= 0 || spaceUp > spaceDown)) {
return $('.submenu-content').addClass('dropup');
} else {
return $('.submenu-content').removeClass('dropup');
}
};
linkFunction = function(scope, el, attr) {
var submenuitem;
submenuitem = angular.element('.submenu-item');
$('.submenu-content').removeClass('dropup');
if (attr.icon != null) {
scope.icon = attr.icon;
} else {
scope.icon = 'ion-more';
}
angular.forEach(submenuitem, function(item) {
var ngClick;
ngClick = item.attributes['ng-click'];
if (ngClick && ngClick.value !== '') {
return angular.element(item).bind('click', function() {
return scope.showToggleMenu = false;
});
}
});
scope.showToggleMenu = false;
scope.changeIcon = function() {
if (scope.showToggleMenu === false) {
detectSubmenuPostion();
return scope.showToggleMenu = true;
} else {
return scope.showToggleMenu = false;
}
};
return scope.hideRoomSubmenu = function() {
if (scope.showToggleMenu === false) {
return scope.showToggleMenu = true;
} else {
return scope.showToggleMenu = false;
}
};
};
return {
restrict: 'E',
replace: false,
transclude: true,
templateUrl: 'submenu.tpl.html',
link: linkFunction
};
}
]);
detectSubmenuPostion()
答案 3 :(得分:5)
如果您喜欢使用ES6 Map
,则适合您:
function groupBy(arr, prop) {
const map = new Map(Array.from(arr, obj => [obj[prop], []]));
arr.forEach(obj => map.get(obj[prop]).push(obj));
return Array.from(map.values());
}
const data = [{ name: "Display", group: "Technical detals", id: 60, value: 4 }, { name: "Manufacturer", group: "Manufacturer", id: 58, value: "Apple" }, { name: "OS", group: "Technical detals", id: 37, value: "Apple iOS" }];
console.log(groupBy(data, "group"));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Map
实例是根据从输入数组生成的键/值对创建的。键是要分组的属性的值,并且这些值被初始化为空数组。
然后填充这些数组。最后,返回地图的值(即那些填充的数组)。
答案 4 :(得分:1)
Reduce非常适合这种情况。以下给出的list
是您的输入数据:
const list = [{
'name': 'Display',
'group': 'Technical detals',
'id': '60',
'value': '4'
},
{
'name': 'Manufacturer',
'group': 'Manufacturer',
'id': '58',
'value': 'Apple'
},
{
'name': 'OS',
'group': 'Technical detals',
'id': '37',
'value': 'Apple iOS'
}
];
const groups = list.reduce((groups, item) => {
const group = (groups[item.group] || []);
group.push(item);
groups[item.group] = group;
return groups;
}, {});
console.log(groups);
如果您想保持不变,则可以这样编写reduce
:
const list = [{
'name': 'Display',
'group': 'Technical detals',
'id': '60',
'value': '4'
},
{
'name': 'Manufacturer',
'group': 'Manufacturer',
'id': '58',
'value': 'Apple'
},
{
'name': 'OS',
'group': 'Technical detals',
'id': '37',
'value': 'Apple iOS'
}
];
const groups = list.reduce((groups, item) => ({
...groups,
[item.group]: [...(groups[item.group] || []), item]
}), {});
console.log(groups);
取决于您的环境是否允许扩展语法。
答案 5 :(得分:1)
有点不同,所以我们有一个简单的对象列表,想按属性对它进行分组,但要包括所有相关的
[ {'group':'1', 'names':['name1', 'name4']},
{'group':'2', 'names':['name2', 'name3']}
所以结果应该是:
{{1}}
答案 6 :(得分:0)
如果您使用的是lodash,则可以使用groupBy
。
它支持数组和对象。
示例:
_.groupBy([6.1, 4.2, 6.3], Math.floor);
// => { '4': [4.2], '6': [6.1, 6.3] }
// The `_.property` iteratee shorthand.
_.groupBy(['one', 'two', 'three'], 'length');
// => { '3': ['one', 'two'], '5': ['three'] }
答案 7 :(得分:0)
我尝试使用标记为已接受的答案,但注意到某些组中缺少元素,具体取决于所评估的属性类型。这是从该答案得出的解决方案:
function groupBy(collection, property) {
var i = 0, values = [], result = [];
for (i; i < collection.length; i++) {
if(values.indexOf(collection[i][property]) === -1) {
values.push(collection[i][property]);
result.push(collection.filter(function(v) { return v[property] === collection[i][property] }));
}
}
return result;
}
var obj = groupBy(list, "group");
答案 8 :(得分:0)
尝试
function Test() {}
let tmp = function() {
console.log(this)
}
tmp.call(Test)
setTimeout(() => {
(function() {
console.log(this)
}).call(Test)
}, 100);
let g = (d,h={},r={},i=0)=>(d.map(x=>(y=x.group,h[y]?1:(h[y]=++i,r[h[y]-1]=[]),r[h[y]-1].push(x))),r);
console.log( g(data) );
答案 9 :(得分:0)
让我们说您的初始数组已分配给data
data.reduce((acc, d) => {
if (Object.keys(acc).includes(d.group)) return acc;
acc[d.group] = data.filter(g => g.group === d.group);
return acc;
}, {})
这会给你类似的东西
{
"Technical detals" = [
{
'group' = 'Technical detals',
'name' = 'Display',
'id' = '60',
'value' = '4'
},
{
'group' = 'Technical detals',
'name' = 'OS',
'id' = '37',
'value' = 'Apple iOS'
}],
"Manufacturer" = [
{
'group' = 'Manufacturer',
'name' = 'Manufacturer',
'id' = '58',
'value' = 'Apple'
}]
}
答案 10 :(得分:0)
根据 Anthony Awuley 答案,我为 TypeScript 准备了通用解决方案!
const groupBy = <T, K extends keyof T>(value: T[], key: K) =>
value.reduce((acc, curr) => {
if (acc.get(curr[key])) return acc;
acc.set(curr[key], value.filter(elem => elem[key] === curr[key]));
return acc;
}, new Map<T[K], T[]>());