使用lodash .groupBy。如何添加自己的键以进行分组输出?

问题描述 投票:0回答:12

我有从 API 返回的示例数据。

我正在使用 Lodash 的

_.groupBy
将数据转换为我可以更好使用的对象。 返回的原始数据是这样的:

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

我希望

_.groupBy
函数返回一个如下所示的对象:

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

目前我正在使用

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

正在返回这个。

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

分组是正确的,但我真的很想添加我想要的键(

color
users
)。使用
_.groupBy
可以吗?或者其他一些
LoDash
实用程序?

javascript sorting underscore.js grouping lodash
12个回答
227
投票

您可以在 Underscore 和 Lodash(3.x 和 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>


原答案

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

在线演示

注意: Lodash 4.0 开始,

.pairs
函数已重命名为
_.toPairs()


124
投票

是不是这么简单?

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

31
投票

最高投票的答案使用 Lodash

_.chain
函数,现在被认为是一种不好的做法 “为什么使用
_.chain
是一个错误。”

这里有一些从 函数式编程 角度解决问题的建议:

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)

其中

input
是要转换的数组。


26
投票

另一种方式

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

8
投票

谢谢@thefourtheye,您的代码很有帮助。 我使用 Lodash 4.5.0 版本从您的解决方案创建了一个通用函数。

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

使用方法:

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

这是更新后的 fiddler;

https://jsfiddle.net/sc2L9dby/


6
投票

使用

lodash
其他答案看起来不错。

我会建议使用 JavaScript 的不同方法,例如

Array#reduce
object for storing
??=
语法。结果,只需要
O(n)
时间复杂度。

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

const result = data.reduce((acc, {
  name,
  color,
  age
}) => {
  acc[color] ??= {
    color: color,
    users: []
  };
  acc[color].users.push({
    name,
    color,
    age
  });

  return acc;
}, {});
console.log(Object.values(result));


5
投票

这是使用 lodash 4 和 ES6 的更新版本

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

3
投票

使用 Lodash 4.17.4 的示例 groupBy 和列求和

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

2
投票

我建议采用不同的方法,使用我自己的库,您可以用几行代码完成此操作:

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

var result = groupMe(collection);

这对于 lodash 或 Underscore 来说有点困难,因为参数的顺序相反,所以你必须经常使用

_.partial


0
投票

  const groupBy = (array, key, name) => {
    return array.reduce((result, obj) => {
      result[obj[key]] = result[obj[key]] || {
        location: obj[name],
        child: [],
      };
      // result[obj[key]] ??= {
      //   location: obj[name],
      //   child: []
      // };
      result[obj[key]].child.push(obj);
      return result;
    }, {});
  };

  const items = [
    {
      id: 1,
      age: 75,
      name: 'Kumar',
      location: 'chennai',
    },
    {
      id: 1,
      age: 25,
      name: 'Christo',
      location: 'Dindigul',
    },
    {
      id: 1,
      age: 28,
      name: 'SK',
      location: 'chennai',
    },
    {
      id: 1,
      age: 21,
      name: 'Ram',
      location: 'chennai',
    },
    {
      id: 1,
      age: 21,
      name: 'ravi',
      location: 'chennai',
    },
  ];

  let obj = groupBy(items, 'age', 'location');
  const result = Object.keys(obj).map((key) => [obj[key]][0]);
  console.log(result);

 


0
投票

ES2024

您现在可以将内置

Object.groupBy()
Map.groupBy()
与旧版
map()
结合使用。不再需要
lodash
underscore.js
或类似的东西:

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

const usersByColor = Object.groupBy(input, (user) => user.color);
const result = Object.entries(usersByColor).map(([color, users]) => ({
  color,
  users,
}));
console.log(JSON.stringify(result, null, 4));
/* Stackoverflow: show only console */
.as-console-wrapper {
  max-height: 100% !important;
  top: 0;
}


-2
投票

2017年就这样做

_.chain(data)
  .groupBy("color")
  .toPairs()
  .map(item => _.zipObject(["color", "users"], item))
  .value();
© www.soinside.com 2019 - 2024. All rights reserved.