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

20

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

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

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

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

<code>var multiGroup = ['size', 'category'];
</code>

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

<code>_.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);
</code>

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

<code>            });
        })
        return result;
    }
});

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

    var testVal = item["size"];

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

    return testVal

}, multiGroup);
</code>
пример ввода и желаемого вывода, вероятно, поможет ... ggozad
Ввод в скрипку наверху, вывод, как это ...jsfiddle.net/rickysullivan/G9sd6 rickysullivan
Что такоеval должен делать? Вы сказали, что передаете массив строк (или функций, я не против) Bergi
На самом деле, эта версия ...jsfiddle.net/rickysullivan/G9sd6/1 rickysullivan

Ваш Ответ

8   ответов
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));
  });
}
}
});    
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();
    }
  }
});
13

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

console.log(_.groupBy(getProperties(), function(record){
    return (record.size+record.category);
}));
Error: User Rate Limit Exceeded
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

1

Underscore.NestИрэн Рос.

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

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

}
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гнездо оператор. Увидетьэтот смысл для деталей иэта скрипка для демонстрации использования с вашим примером.

Error: User Rate Limit Exceeded
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);
    }),
});

Похожие вопросы