web-dev-qa-db-ja.com

JavaScriptでプロパティごとにオブジェクトをグループ化する

これを変換する方法:

[
    {food: 'Apple', type: 'fruit'},
    {food: 'potato', type: 'vegetable'},
    {food: 'banana', type: 'fruit'},
]

これに:

[
    {type: 'fruit', foods: ['Apple', 'banana']},
    {type: 'vegetable', foods: ['potato']}
]

javaScriptまたはアンダースコアを使用

29
user1000952

元のリストがlistという名前の変数に含まれていると仮定します。

_
.chain(list)
.groupBy('type')
.map(function(value, key) {
    return {
        type: key,
        foods: _.pluck(value, 'food')
    }
})
.value();
87
Anurag

アンダースコアを使用しない場合:

var origArr = [
    {food: 'Apple', type: 'fruit'},
    {food: 'potato', type: 'vegetable'},
    {food: 'banana', type: 'fruit'}
];

/*[
    {type: 'fruit', foods: ['Apple', 'banana']},
    {type: 'vegetable', foods: ['potato']}
]*/

function transformArr(orig) {
    var newArr = [],
        types = {},
        i, j, cur;
    for (i = 0, j = orig.length; i < j; i++) {
        cur = orig[i];
        if (!(cur.type in types)) {
            types[cur.type] = {type: cur.type, foods: []};
            newArr.Push(types[cur.type]);
        }
        types[cur.type].foods.Push(cur.food);
    }
    return newArr;
}

console.log(transformArr(origArr));

デモ:http://jsfiddle.net/ErikE/nSLua/3/

クレジットは@ ErikEになります。元のコードを改善/削減して、冗長性を支援しました:)

17
Ian

ここに、@ Ianの答えの少し異なるがより一般的なバージョンがあります

警告:結果はOPの要件とわずかに異なりますが、この質問につまずく私のような他の人は、より一般的な答えIMHOの恩恵を受ける可能性があります

var origArr = [
   {food: 'Apple', type: 'fruit'},
   {food: 'potato', type: 'vegetable'},
   {food: 'banana', type: 'fruit'}
];

function groupBy(arr, key) {
        var newArr = [],
            types = {},
            newItem, i, j, cur;
        for (i = 0, j = arr.length; i < j; i++) {
            cur = arr[i];
            if (!(cur[key] in types)) {
                types[cur[key]] = { type: cur[key], data: [] };
                newArr.Push(types[cur[key]]);
            }
            types[cur[key]].data.Push(cur);
        }
        return newArr;
}

console.log(groupBy(origArr, 'type'));

jsfiddle here を見つけることができます

6
Obi Onuorah
var foods = [
    {food: 'Apple', type: 'fruit'},
    {food: 'potato', type: 'vegetable'},
    {food: 'banana', type: 'fruit'}
];

var newFoods = _.chain( foods ).reduce(function( memo, food ) {
  memo[ food.type ] = memo[ food.type ] || [];
  memo[ food.type ].Push( food.food );
  return memo;
}, {}).map(function( foods, type ) {
    return {
        type: type,
        foods: foods
    };
}).value();

http://jsbin.com/etaxih/2/edit

3
jcreamer898

この古い質問に対するES6ソリューション:

Array#reduce を使用して反復し、グループごとに項目を収集して Map にします。 spreadを使用して、 Map#values を配列に戻します:

const data = [
    {food: 'Apple', type: 'fruit'},
    {food: 'potato', type: 'vegetable'},
    {food: 'banana', type: 'fruit'},
];

const result = [...data.reduce((hash, { food, type }) => {
  const current = hash.get(type) || { type, foods: [] };
  
  current.foods.Push({ food });
  
  return hash.set(type, current);
}, new Map).values()];

console.log(result);
3
Ori Drori

次のような他のES6機能を使用することもできます。

function groupArray(arr, groupBy, keepProperty) {
        let rArr = [], i;
        arr.forEach(item => {
            if((i = rArr.findIndex(obj => obj[groupBy] === item[groupBy])) !== -1)
                rArr[i][`${keepProperty}s`].Push(item[keepProperty]);
            else rArr.Push({
                [groupBy]: item[groupBy],
                [`${keepProperty}s`]: [item[keepProperty]]
            });
        });
        return rArr;
    }

    groupArray(yourArray, 'type', 'food');
0
Justin Levine

Alasqlライブラリを使用して、フィールドの1つでオブジェクトの配列をグループ化できます。この例では、例のとおりに配列を圧縮します。

var res = alasql('SELECT type, ARRAY(food) AS foods FROM ? GROUP BY type',[food]);

この例を試してください at jsFiddle

0
agershun