2017/02/06

【JavaScript】オブジェクトの配列をKeyで集計(グルーピング)する方法

配列内のオブジェクトのキーを使って、抽出したり、集計したり、グルーピングしたいときがある。
// 元データ
[
  { name: 'taro', age: 10 },
  { name: 'jiro', age: 20, email: 'jiro@example.com' },
  { name: 'saburo', age: 30, email: 'saburo@example.com' }  
]

// 欲しいデータ(ユーザごとではなくそれぞれのフィールドでグルーピングしたい)
{
  name: ['taro', 'jiro', 'saburo'],
  age: [10, 20, 30],
  email: ['jiro@example.com', 'saburo@example.com']
}

このようにデータを変換するため、lodash(underscore.js)、ES2015(ES6)、ES5のそれぞれの実装方法をまとめる。


オブジェクトの配列をKeyで集成(グルーピング)する

lodash(underscore.js)が使える場合


const target = [
  {
    name: 'taro',
    age : 10
  },
  {
    name : 'jiro',
    age  : 20,
    email: 'jiro@example.com'
  },
  {
    name : 'saburo',
    age  : 30,
    email: 'saburo@example.com'
  }
]

const tallyTarget = target => {
  // ObjectからKeyを重複なく取得
  const keys = _.uniq(_.flatten(target.map(t => Object.keys(t))))
  // keyで抽出する(pluck)
  const result = {}
  keys.forEach(k => result[k] = _.compact(_.map(target, k)))
  return result
}

// {
//   name : ['taro', 'jiro', 'saburo'],
//   age  : [10, 20, 30],
//   email: ['jiro@example.com', 'saburo@example.com']
// }
console.log(tallyTarget(target))


ライブラリを使わずES2015(ES6)で書く場合


const tallyTarget = target => {
  // flatten
  const _keys = target.map(a => Object.keys(a)).reduce((a, b) => a.concat(b))
  // unique
  const keys = Array.from(new Set(_keys))

  const result = {}
  keys.forEach(k => {
    // pluck & compact
    result[k] = target.map(t => t[k]).filter(t => !!t)
  })
  return result
}



ちょっと古いブラウザを対応する場合

Internet Explorer 11など最新のブラウザなら問題ないのだが、IE9以前は闇すぎるので対象外とする。(IE9以前も対応するならライブラリを使うのが賢明)
ES2015とかわる部分は重複排除の部分。

var tallyTarget = function (target) {
  // flatten
  var _keys = target.map(function (a) {
    return Object.keys(a);
  }).reduce(function (a, b) {
    return a.concat(b);
  });
  // unique
  var keys = _keys.filter(function (a, i, self) {
    return self.indexOf(a) === i;
  });

 var result = {};
  keys.forEach(function (k) {
    // pluck & compact
    result[k] = target.map(function (t) {
      return t[k];
    }).filter(function (t) {
      return !!t;
    });
  });
  return result;
};


参考サイト




以上

written by @bc_rikko

0 件のコメント :

コメントを投稿