Группируйте коллекцию в коллекцию коллекций по значению ключа в JavaScript

#javascript #arrays #ecmascript-6 #collections #group-by

#javascript #массивы #ecmascript-6 #Коллекции #группировать по

Вопрос:

У меня есть коллекция элементов, как показано ниже:

 [
    { Number: 1, Description: "Example description 1"},
    { Number: 1, Description: "Example description 2"},
    { Number: 2, Description: "Example description 3"},
    { Number: 2, Description: "Example description 4"}
]
 

Я хотел бы сгруппировать ее по Number свойству, чтобы получить следующий результат:

 [
    [
        { Number: 1, Description: "Example description 1"},
        { Number: 1, Description: "Example description 2"}
    ]
    [
        { Number: 2, Description: "Example description 3"},
        { Number: 2, Description: "Example description 4"}
    ]
]
 

Следующая функция почти работает для меня:

 var groupBy = function(xs, key) {

      return xs.reduce(function(rv, x) {
            (rv[x[key]] = rv[x[key]] || []).push(x);
            return rv;
      }, {});
}
 

но он возвращает объект со свойствами, где каждое свойство является массивом. Это не позволяет мне использовать map для этого функцию.

Как я могу преодолеть это, чтобы получить возможность использовать массив массивов map ?

Ответ №1:

Вы можете получить значения из объекта.

 const
    groupBy = function(xs, key) {
        return Object.values(xs.reduce(function(rv, x) {
            (rv[x[key]] = rv[x[key]] || []).push(x);
            return rv;
        }, {}));
    },
    data = [{ Number: 1, Description: "Example description 1" }, { Number: 1, Description: "Example description 2" }, { Number: 2, Description: "Example description 3" }, { Number: 2, Description: "Example description 4" }];
    
console.log(groupBy(data, 'Number')); 
 .as-console-wrapper { max-height: 100% !important; top: 0; } 

Ответ №2:

Лучший способ — использовать reduce функцию, которая позволяет вам перебирать результат. Затем вы можете создать create array в цикле:

 var groupedMap = function(collection, key) { 
      var result = collection.reduce(
      (entryMap, e) => entryMap.set(e[key], [...entryMap.get(e[key])||[], e]),
      new Map());

      var resultArray = [];
      result.forEach(element => {
            resultArray.push(element);
      });

      return resultArray;
}
 

Примером использования этого метода для вашего случая может быть:

 var arrayOfArray = groupedMap(exampleArray, 'Number');
 

Теперь вы можете вызвать функцию map arrayOfArray .
Обратите внимание, что это решение не будет работать IE11 , поскольку оно совместимо с ES6 .