Группировать по массиву и добавлять поля и вспомогательные массивы в основной массив

У меня такой тяжелый массив:

[
  {Id: 1, Name: 'Red', optionName: 'Color'}, 
  {Id: 2, Name: 'Yellow', optionName: 'Color'},
  {Id: 3, Name: 'Blue', optionName: 'Color'},
  {Id: 4, Name: 'Green', optionName: 'Color'},
  {Id: 7, Name: 'Black', optionName: 'Color'},
  {Id: 8, Name: 'S', optionName: 'Size'},
  {Id: 11, Name: 'M', optionName: 'Size'},
  {Id: 12, Name: 'L', optionName: 'Size'},
  {Id: 13, Name: 'XL', optionName: 'Size'},
  {Id: 14, Name: 'XXL', optionName: 'Size'}
]

Что мне нужно сделать, это сгруппировать их с помощью optionName и иметь две строки в основном массиве:

[
  {
    Name: 'Color',
    Data:[{Id: 1, Name: 'Red'},
          {Id: 2, Name: 'Yellow'},
          {Id: 3, Name: 'Blue'},
          {Id: 4, Name: 'Green'},
          {Id: 7, Name: 'Black'}]
  }, {
    Name: 'Size',
    Data:[{Id: 8, Name: 'S'},
          {Id: 11, Name: 'M'},
          {Id: 12, Name: 'L'},
          {Id: 13, Name: 'XL'},
          {Id: 14, Name: 'XXL'}]
  }
]

Как это сделать в javascript?

Ответ 1

Это фрагмент, который я написал для подобных ситуаций. Вы можете добавить эту функциональность ко всем вашим массивам:

Object.defineProperty(Array.prototype, 'group', {
  enumerable: false,
  value: function (key) {
    var map = {};
    this.forEach(function (e) {
      var k = key(e);
      map[k] = map[k] || [];
      map[k].push(e);
    });
    return Object.keys(map).map(function (k) {
      return {key: k, data: map[k]};
    });
  }
});

Вы можете использовать это так. Вы можете просто передать функцию, которая определяет, как вы хотите сгруппировать ваши данные.

var newArray = arr.group(function (item) {
  return item.optionName;
});

Рабочая скрипка

Если вам нужно, вы можете заменить {key: k, data: map[k]} на {Name: k, Data: map[k]}.


Это также более компактная версия кода выше для ES6:

Object.defineProperty(Array.prototype, 'group', {
  enumerable: false,
  value: function (key) {
    let map = {};
    this.map(e => ({k: key(e), d: e})).forEach(e => {
      map[e.k] = map[e.k] || [];
      map[e.k].push(e.d);
    });
    return Object.keys(map).map(k => ({key: k, data: map[k]}));
  }
});

Используйте это так:

let newArray = arr.group(item => item.optionName))

Ответ 2

Вы можете использовать сокращение, чтобы получить нужный набор результатов:

var result = list.reduce(function(memo, item) {
  if (item.optionName === 'Color') {
    memo[0].Data.push(
      Id: item.Id,
      Name: item.Name
    });
  }
  if (item.optionName === 'Size') {
    memo[1].Data.push({
      Id: item.Id,
      Name: item.Name
    });
  }
  return memo;
}, [{ Name: 'Color', Data: [] }, { Name: 'Size', Data: [] }]);

список переменных - ваш первый список.

Надеюсь это поможет.

Ответ 3

Решение ES6 с использованием объекта Map:

function groupBy(arr, key) {
  	return arr.reduce(
      (sum, item) => {
      	const groupByVal = item[key];
        groupedItems = sum.get(groupByVal) || [];
        groupedItems.push(item);
      	return sum.set(groupByVal, groupedItems);
        },
      new Map()
      );
}

var Data = [ 
{ Id: 1, Name: 'Red', optionName: 'Color' }, 
  { Id: 2, Name: 'Yellow', optionName: 'Color' },
  { Id: 3, Name: 'Blue', optionName: 'Color' },
  { Id: 4, Name: 'Green', optionName: 'Color' },
  { Id: 7, Name: 'Black', optionName: 'Color' },
  { Id: 8, Name: 'S', optionName: 'Size' },
  { Id: 11, Name: 'M', optionName: 'Size' },
  { Id: 12, Name: 'L', optionName: 'Size' },
  { Id: 13, Name: 'XL', optionName: 'Size' },
  { Id: 14, Name: 'XXL', optionName: 'Size' } ];

document.getElementById("showArray").innerHTML =JSON.stringify([...groupBy(Data, 'optionName')], null, 4); 
<pre id="showArray"></pre>

Ответ 4

Это фрагмент, который я написал для своей ситуации в моей функциональности приложений всех массивов. Этот код фрагмента используется в приложении node js. Все вышеперечисленное - это решение, но я нашел некоторую проблему на стороне сервера в node js.  Этот фрагмент - пользователь, полный меня....

  var Data= [ 
    { Id: 1, Name: 'Red', optionName: 'Color' }, 
      { Id: 2, Name: 'Yellow', optionName: 'Color' },
      { Id: 3, Name: 'Blue', optionName: 'Color' },
      { Id: 4, Name: 'Green', optionName: 'Color' },
      { Id: 7, Name: 'Black', optionName: 'Color' },
      { Id: 8, Name: 'S', optionName: 'Size' },
      { Id: 11, Name: 'M', optionName: 'Size' },
      { Id: 12, Name: 'L', optionName: 'Size' },
      { Id: 13, Name: 'XL', optionName: 'Size' },
      { Id: 14, Name: 'XXL', optionName: 'Size' } ];

    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;
}

Я использую его так. Я просто передаю функцию, которая определяет, как вы хотите группировать наши данные.

filterData= groupBy(Data,'optionName');

Результат этого фрагмента вывода кода.....

 [
{"type":"Color","data":[{"Id":1,"Name":"Red","optionName":"Color"},
                       {"Id":2,"Name":"Yellow","optionName":"Color"},
                       {"Id":3,"Name":"Blue","optionName":"Color"}, 
                       {"Id":4,"Name":"Green","optionName":"Color"},
                       {"Id":7,"Name":"Black","optionName":"Color"}]},
{"type":"Size","data":[{"Id":8,"Name":"S","optionName":"Size"},
                       {"Id":11,"Name":"M","optionName":"Size"},
                       {"Id":12,"Name":"L","optionName":"Size"},
                       {"Id":13,"Name":"XL","optionName":"Size"},
                       {"Id":14,"Name":"XXL","optionName":"Size"}]}
]

Показать на скрипке

Ответ 5

var originalList = [ { Id: 1, Name: 'Red', optionName: 'Color' }, 
  { Id: 2, Name: 'Yellow', optionName: 'Color' },
  { Id: 3, Name: 'Blue', optionName: 'Color' },
  { Id: 4, Name: 'Green', optionName: 'Color' },
  { Id: 7, Name: 'Black', optionName: 'Color' },
  { Id: 8, Name: 'S', optionName: 'Size' },
  { Id: 11, Name: 'M', optionName: 'Size' },
  { Id: 12, Name: 'L', optionName: 'Size' },
  { Id: 13, Name: 'XL', optionName: 'Size' },
  { Id: 14, Name: 'XXL', optionName: 'Size' } ];

var output = [{ Name: "Color", Data: [] },{ Name: "Size", Data: [] }] ;

originalList.map(function(entry){
    if ( entry.optionName === "Color") output[0].Data.push({ Id: entry.Id, Name: entry.Name });
    if ( entry.optionName === "Size") output[1].Data.push({ Id: entry.Id, Name: entry.Name });
});

Ответ 6

'use strict'

let l = [ { Id: 1, Name: 'Red', optionName: 'Color' }, 
          { Id: 2, Name: 'Yellow', optionName: 'Color' },
          { Id: 3, Name: 'Blue', optionName: 'Color' },
  { Id: 4, Name: 'Green', optionName: 'Color' },
  { Id: 7, Name: 'Black', optionName: 'Color' },
  { Id: 8, Name: 'S', optionName: 'Size' },
  { Id: 11, Name: 'M', optionName: 'Size' },
  { Id: 12, Name: 'L', optionName: 'Size' },
  { Id: 13, Name: 'XL', optionName: 'Size' },
  { Id: 14, Name: 'XXL', optionName: 'Size' } ];


let color = [];
let size  = [];

l.forEach(element => {
    if (element['optionName'] === 'Color') {
      color.push({'Id': element.Id, 'Name': element.Name});
    } else {
      size.push({'Id': element.Id, 'Name': element.Name});
    }
});  


console.log(color);
console.log(size);

Вы можете попробовать этот метод.

Ответ 7

Все ответы приводят к одному и тому же результату, поэтому все сводится к личным предпочтениям (или рекомендациям компании) о том, как справиться с этим.

//  ES5 (traditional javascript) version
function groupByOptionName(list, optionName) {
    return list
        //  filter out any item whose optionName does not match the desired name
        .filter(function(item) {
            return item.optionName === optionName;
        })
        //  map the item into the desired shape 
        //  (appears to be everything except optionName itself
        .map(function(item) {
            return {
                Id: item.Id,
                Name: item.Name
            };
        })
}

//  ES2015/ES6 version
function groupByOptionName(list, optionName) {
    return list
        //  filter out any item whose optionName does not match the desired name
        .filter(item => item.optionName === optionName)
        //  map the item into the desired shape 
        //  (appears to be everything except optionName itself
        .map(item => {
            Id: item.Id,
            Name: item.Name
        });
}

Эта функция позволит вам запрограммировать желаемый результат следующим образом:

var output = [
    {Name: 'Color', Data: groupByOptionName(list, 'Color')},
    {Name: 'Size', Data: groupByOptionName(list, 'Size')},
];
//  the ES2015/ES6 version of this code would replace var with let

В то время как сам код отличается, он очень похож на другие ответы, и только вариация необходимых шагов.

Можно также исключить любые имена жестко запрограммированных опций (Color и Size), извлекая эти данные, это позволит использовать более динамический ввод, но также может потребовать больше обработки, которая действительно необходима.

//  ES5 (traditional javascript) version
function getOptionNames(list) {
    return list
        //  map the array into a list of optionNames
        .map(function(item) {
            return item.optionName;
        })
        //  remove duplicates
        .filter(function(item, index, all) {
            return all.indexOf(item) === index;
        });
}

//  ES2015/ES6 version (does exactly the same as the one above)
function getOptionNames(list) {
    return list
        //  map the array into a list of optionNames
        .map(item => item.optionName)
        //  remove duplicates
        .filter((item, index, all) => all.indexOf(item) === index);
}

Это позволяет полностью получить результат на основе входных данных:

//  ES5 (traditional javascript) version
var output = getOptionNames(list)
        //  map the names into the desired structure
        .map(function(buffer, name) {
            return {
                Name: name,
                Data: groupByOptionName(list, name)
            };
        });

//  ES2015/ES6 version (does exactly the same as the one above)
var output = getOptionNames(list)
        //  map the names into the desired structure
        .map((buffer, name) => {
            Name: name,
            Data: groupByOptionName(list, name)
        });

Записывая все шаги обработки данных короткими последовательными шагами, вы сделаете сами (особенно ваше будущее), если этот код когда-либо понадобится отрегулировать.

Если набор данных действительно тяжелый (с точки зрения большого количества данных), вы также должны быть уверены, что количество копий, которые вы держите в памяти, ограничено. Например, если вам не нужен исходный набор данных, убедитесь, что он может быть собран с помощью мусора (не имея переменной, содержащую ее за пределами области, в которой вы получаете данные).

Ответ 8

Применение:

groupValues([
    { color: 'blue', value: 100 }, 
    { color: 'blue', value: 75 }, 
    { color: 'yellow', value: 50 },
    { color: 'yellow', value: 25 }
], 'color')

Результат:

[
    [{ color: 'blue', value: 100 }, { color: 'blue', value: 75 }],
    [{ color: 'yellow', value: 50 }, { color: 'yellow', value: 25 }] 
]

Функция:

const groupValues = function(arr, key) {
    const mapped = {}
    arr.forEach(el => {
        const actualKey = el[key]
        if(!mapped.hasOwnProperty(actualKey)) mapped[actualKey] = []

        mapped[actualKey].push(el)
    })
    return Object.keys(mapped).map(el => mapped[el])
}