javascript |对象分组

时间:2014-02-14 10:11:01

标签: javascript object merge grouping

我有一个对象。它看起来如下:

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

如何分组我的第一个对象?

11 个答案:

答案 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];
   }
});

您可以在行动http://jsfiddle.net/nkVu6/3/

中看到这两个示例

答案 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)

使用AWS managed policyreduce

让我们说您的初始数组已分配给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[]>());