20

Вопрос по arrays – Underscore.js groupBy несколько значений

Используя Underscore.js, я пытаюсь сгруппировать список элементов несколько раз, т.е.

Группировать по размеру, затем по каждому размеру, группировать по категориям ...

http://jsfiddle.net/rickysullivan/WTtXP/1/

В идеале я бы хотел иметь функцию или расширить_.groupBy() так что вы можете бросить в него массив с параметрами для группировки.

var multiGroup = ['size', 'category'];

Вероятно, мог бы просто сделать миксин ...

_.mixin({
    groupByMulti: function(obj, val, arr) {
        var result = {};
        var iterator = typeof val == 'function' ? val : function(obj) {
                return obj[val];
            };
        _.each(arr, function(arrvalue, arrIndex) {
            _.each(obj, function(value, objIndex) {
                var key = iterator(value, objIndex);
                var arrresults = obj[objIndex][arrvalue];
                if (_.has(value, arrvalue))
                    (result[arrIndex] || (result[arrIndex] = [])).push(value);

У меня болит голова, но я думаю, что здесь нужно больше подталкивать ...

            });
        })
        return result;
    }
});

properties = _.groupByMulti(properties, function(item) {

    var testVal = item["size"];

    if (parseFloat(testVal)) {
        testVal = parseFloat(item["size"])
    }

    return testVal

}, multiGroup);
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от
  • Что такоеval должен делать? Вы сказали, что передаете массив строк (или функций, я не против)

    от Bergi
  • Ввод в скрипку наверху, вывод, как это ...jsfiddle.net/rickysullivan/G9sd6

    от rickysullivan
  • На самом деле, эта версия ...jsfiddle.net/rickysullivan/G9sd6/1

    от rickysullivan
  • пример ввода и желаемого вывода, вероятно, поможет ...

    от ggozad
8 ответов
  • 39

    Простая рекурсивная реализация:

    _.mixin({
      /*
       * @mixin
       *
       * Splits a collection into sets, grouped by the result of running each value
       * through iteratee. If iteratee is a string instead of a function, groups by
       * the property named by iteratee on each of the values.
       *
       * @param {array|object} list - The collection to iterate over.
       * @param {(string|function)[]} values - The iteratees to transform keys.
       * @param {object=} context - The values are bound to the context object.
       * 
       * @returns {Object} - Returns the composed aggregate object.
       */
      groupByMulti: function(list, values, context) {
        if (!values.length) {
          return list;
        }
        var byFirst = _.groupBy(list, values[0], context),
            rest    = values.slice(1);
        for (var prop in byFirst) {
          byFirst[prop] = _.groupByMulti(byFirst[prop], rest, context);
        }
        return byFirst;
      }
    });
    

    Демо в вашем jsfiddle

  • 0

    Пример с Лодашем и Миксином

    _.mixin({
    'groupByMulti': function (collection, keys) {
    if (!keys.length) {
     return collection;
     } else {
      return _.mapValues(_.groupBy(collection,_.first(keys)),function(values) {
        return _.groupByMulti(values, _.rest(keys));
      });
    }
    }
    });    
    

  • 13

    Как насчет этого довольно простого взлома?

    console.log(_.groupBy(getProperties(), function(record){
        return (record.size+record.category);
    }));
    

  • 0

    Вот простая для понимания функция.

    function mixin(list, properties){
    
        function grouper(i, list){
    
            if(i < properties.length){
                var group = _.groupBy(list, function(item){
                    var value = item[properties[i]];
                    delete item[properties[i]];
                    return value;
                });
    
                _.keys(group).forEach(function(key){
                    group[key] = grouper(i+1, group[key]);
                });
                return group;
            }else{
                return list;
            }
        }
    
        return grouper(0, list);
    
    }
    

  • 0

    Группировка по составному ключу работает лучше для меня в большинстве

    ситуаций:

    const groups = _.groupByComposite(myList, ['size', 'category']);
    

    Демонстрация с использованием OP-скрипки

    Mixin
    _.mixin({
      /*
       * @groupByComposite
       *
       * Groups an array of objects by multiple properties. Uses _.groupBy under the covers,
       * to group by a composite key, generated from the list of provided keys.
       *
       * @param {Object[]} collection - the array of objects.
       * @param {string[]} keys - one or more property names to group by.
       * @param {string} [delimiter=-] - a delimiter used in the creation of the composite key.
       *
       * @returns {Object} - the composed aggregate object.
       */
      groupByComposite: (collection, keys, delimiter = '-') =>
        _.groupBy(collection, (item) => {
          const compositeKey = [];
          _.each(keys, key => compositeKey.push(item[key]));
          return compositeKey.join(delimiter);
        }),
    });
    

  • 0

    Усовершенствования по методу joyrexus в методе Берги не используют пре

    имущества системы смешивания подчеркивания / lodash. Вот это как миксин:

    _.mixin({
      nest: function (collection, keys) {
        if (!keys.length) {
          return collection;
        } else {
          return _(collection).groupBy(keys[0]).mapValues(function(values) {
            return _.nest(values, keys.slice(1));
          }).value();
        }
      }
    });
    

  • 1

    Проверьте это расширение подчеркивания:

    Underscore.NestИрэн Рос.

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

  • 16

    Я думаю

    что ответ @ Bergi's можно немного упростить, используя Lo-Dash.mapValues  (для отображения функций на значения объекта). Это позволяет нам группировать записи в массиве по нескольким ключам во вложенном виде:

    _ = require('lodash');
    
    var _.nest = function (collection, keys) {
      if (!keys.length) {
        return collection;
      }
      else {
        return _(collection).groupBy(keys[0]).mapValues(function(values) { 
          return nest(values, keys.slice(1));
        }).value();
      }
    };
    

    Я переименовал метод вnest потому что в конечном итоге он выполняет ту же роль, которую выполняют D3гнездо оператор. Увидетьэтот смысл для деталей иэта скрипка для демонстрации использования с вашим примером.