usando lodash .groupBy. ¿Cómo agregar sus propias claves para la salida agrupada?


104

Tengo estos datos de muestra devueltos desde una API.

Estoy usando Lodash's _.groupBypara convertir los datos en un objeto que puedo usar mejor. Los datos brutos devueltos son los siguientes:

[
    {
        "name": "jim",
        "color": "blue",
        "age": "22"
    },
    {
        "name": "Sam",
        "color": "blue",
        "age": "33"
    },
    {
        "name": "eddie",
        "color": "green",
        "age": "77"
    }
]

Quiero que la _.groupByfunción devuelva un objeto que se parece a esto:

[
    {
        color: "blue",
        users: [
            {
                "name": "jim",
                "color": "blue",
                "age": "22"
            },
            {
                "name": "Sam",
                "color": "blue",
                "age": "33"
            }
        ]
    },
    {
        color: "green",
        users: [
            {
                "name": "eddie",
                "color": "green",
                "age": "77"
            }
        ]
    }
]

Actualmente estoy usando

_.groupBy(a, function(b) { return b.color})

que está devolviendo esto.

{blue: [{..}], green: [{...}]}

las agrupaciones son correctas, pero realmente me gustaría agregar las claves que quiero ( color, users). ¿Es esto posible el uso _.groupBy? o alguna otra LoDashutilidad?

Respuestas:


140

Puedes hacerlo así en Lodash 4.x

var data = [{
  "name": "jim",
  "color": "blue",
  "age": "22"
}, {
  "name": "Sam",
  "color": "blue",
  "age": "33"
}, {
  "name": "eddie",
  "color": "green",
  "age": "77"
}];

console.log(
  _.chain(data)
    // Group the elements of Array based on `color` property
    .groupBy("color")
    // `key` is group's name (color), `value` is the array of objects
    .map((value, key) => ({ color: key, users: value }))
    .value()
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>


Respuesta original

var result = _.chain(data)
    .groupBy("color")
    .pairs()
    .map(function(currentItem) {
        return _.object(_.zip(["color", "users"], currentItem));
    })
    .value();
console.log(result);

Demo en línea

Nota: Lodash 4.0 en adelante, la .pairsfunción ha sido renombrada a_.toPairs()


Muy ingenioso, pero difícil de entender. ¿Puede explicar los pasos intermedios, especialmente el emparejamiento y la cremallera (y la cremallera doble, ya que _.objectes un alias de _.zipObject)?
Benny Bottema

3
lodash 3.10.0 y algunos registros para cada paso: jsfiddle.net/plantface/WYCF8/171 . Sigue siendo un rompecabezas, pero estoy llegando. No he usado _.zipy _.pairtanto todavía.
Benny Bottema

12
En lodash 4.x, el pairs()método ya no existe. Una versión actualizada de lodash 4.0 de este ejemplo es:.chain(data).groupBy('color') .toPairs().map(function (pair) { return _.zipObject(['Name', 'Suppliers'], air); }).value();
Erik Schierboom

5
Siento que loadash debería tener una función que haga exactamente esto. Creo que los usuarios querrían agrupar una matriz de objetos por una propiedad todo el tiempo.
Adam Klein

1
El uso _.chainse considera ahora una mala práctica.
Pawel

89

¿No es así de simple?

var result = _(data)
            .groupBy(x => x.color)
            .map((value, key) => ({color: key, users: value}))
            .value();

4
Esto me parece mucho más limpio y parece estar dando los mismos resultados. ¡Gracias!
Jeremy A. West

3
Guau. que sintaxis es esta? Primera vez que
veo

Esta debería ser la respuesta aceptada. Simple y limpio.
Tiago Stapenhorst Martins

17

de otra manera

_.chain(data)
    .groupBy('color')
    .map((users, color) => ({ users, color }))
    .value();

Similar a la respuesta de @ thefourtheye pero un poco más fácil de entender
Martin Magakian

Eres mi héroe
AlkanV

17

La respuesta más votada usa la función Lodash _.chain, que ahora se considera una mala práctica "Por qué usar _.chaines un error".

Aquí hay algunos lineamientos que abordan el problema desde la perspectiva de la programación funcional :

import tap from "lodash/fp/tap";
import flow from "lodash/fp/flow";
import groupBy from "lodash/fp/groupBy";

const map = require('lodash/fp/map').convert({ 'cap': false });

const result = flow(
      groupBy('color'),
      map((users, color) => ({color, users})),
      tap(console.log)
    )(input)

¿Dónde inputhay una matriz que desea convertir?


Traté de usar en flow()lugar de chain()aquí, pero la verificación de tipo de mecanografiado simplemente se vuelve loca con las funciones compuestas. Espero que tengamos el mismo nivel de soporte que tenemos actualmente en RxJS pipe(), por ejemplo, en lodash.
BrunoJCM

Realmente me gusta su sintaxis map (), muy genial en map((users, color) => ({color, users}))lugar demap((value, key) => ({ color: key, users: value }))
Gil Epshtain

7

Gracias @thefourtheye , su código ayudó mucho. Creé una función genérica a partir de su solución usando la versión 4.5.0 de Lodash.

function groupBy(dataToGroupOn, fieldNameToGroupOn, fieldNameForGroupName, fieldNameForChildren) {
            var result = _.chain(dataToGroupOn)
             .groupBy(fieldNameToGroupOn)
             .toPairs()
             .map(function (currentItem) {
                 return _.zipObject([fieldNameForGroupName, fieldNameForChildren], currentItem);
             })
             .value();
            return result;
        }

Para usarlo:

var result = groupBy(data, 'color', 'colorId', 'users');

Aquí está el violinista actualizado;

https://jsfiddle.net/sc2L9dby/


5

Aquí hay una versión actualizada usando lodash 4 y ES6

const result = _.chain(data)
    .groupBy("color")
    .toPairs()
    .map(pair => _.zipObject(['color', 'users'], pair))
    .value();

2

Sugeriría un enfoque diferente, usando mi propia biblioteca , podría hacer esto en unas pocas líneas:

var groupMe = sequence(
  groupBy(pluck('color')),
  forOwn(function(acc, k, v) {
    acc.push({colors: k, users: v});
    return acc;
  },[])
);

var result = groupMe(collection);

Esto sería un poco difícil con lodash o subrayado porque los argumentos están en el orden opuesto, por lo que tendrías que usar _.partialmucho.


2

Ejemplo groupBy y suma de una columna usando Lodash 4.17.4

   var data = [{
                "name": "jim",
                "color": "blue",
                "amount": 22
                }, {
                "name": "Sam",
                "color": "blue",
                "amount": 33
                }, {
               "name": "eddie",
               "color": "green",
               "amount": 77
              }];

      var result = _(data)
                   .groupBy(x => x.color)
                   .map((value, key) => 
                   ({color: key,
                    totalamount: _.sumBy(value,'amount'),
                    users: value})).value();

                    console.log(result);

agradable ... y actualizado
Peter van der Lely

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.