算法:lodash的Array. groupBy是怎么实现的?

65 阅读2分钟

lodash的Array. groupBy是怎么实现的?

编写一段可应用于所有数组的代码,使任何数组调用 Array. groupBy(fn) 方法时,它返回对该数组分组后的结果。

数组分组是一个对象,其中的每个键都是 fn(arr[i]) 的输出的一个数组,该数组中含有原数组中具有该键的所有项。

提供的回调函数 fn 将接受数组中的项并返回一个字符串类型的键。每个值列表的顺序应该与元素在数组中出现的顺序相同。任何顺序的键都是可以接受的。

示例 1

输入:
array = [
  {"id":"1"},
  {"id":"1"},
  {"id":"2"}
], 
fn = function (item) { 
  return item.id; 
}
输出:
{ 
  "1": [{"id": "1"}, {"id": "1"}],   
  "2": [{"id": "2"}] 
}
解释:
输出来自函数 array.groupBy(fn)。
分组选择方法是从数组中的每个项中获取 "id" 。
有两个 "id" 为 1 的对象。所以将这两个对象都放在第一个数组中。
有一个 "id" 为 2 的对象。所以该对象被放到第二个数组中。

示例 2:

输入:
array = [
  [1, 2, 3],
  [2, 3, 5],
  [1, 5, 9]
]
fn = function (list) { 
  return String(list[0]); 
}
输出:
{
  "1": [[1, 2, 3], [1, 5, 9]],
  "2": [[2, 3, 5]]
}
解释:
数组可以是任何类型的。在本例中,分组选择方法是将键定义为数组中的第一个元素。
有两个第一个数字为 1 的数组。所以将这两个数组都放在第一个数组中。 
有一个第一个数字为 2 的数组。所以该数组被放到第二个数组中。

示例 3:

输出:
array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
fn = function (n) { 
  return String(n > 5);
}
输入:
{
  "true": [6, 7, 8, 9, 10],
  "false": [1, 2, 3, 4, 5]
}
解释:
分组选择方法是根据每个数字是否大于 5 来分割数组。

为了让任何数组都能调用 groupBy 方法,并返回根据提供的回调函数分组后的结果,我们可以通过在 Array.prototype 上添加这个方法来实现。这样,所有的数组实例都将能够使用这个新的方法。

下面是如何在 Array.prototype 上添加 groupBy 方法的代码:

Array.prototype.groupBy = function(fn) {
    return this.reduce((acc, item) => {
        const key = fn(item);
        if (!acc[key]) {
            acc[key] = [];
        }
        acc[key].push(item);
        return acc;
    }, {});
};

//示例 1:
const arr1=[{"id":"1"}, {"id":"1"}, {"id":"2"}].groupBy(item=>item.id)
console.log("arr1",arr1)
//输出:{ "1": [{"id": "1"}, {"id": "1"}], "2": [{"id": "2"}] }
//示例 2:
const arr2=[[1,2,3],[2,3,5],[1,5,9]].groupBy(list=>String(list[0]))
console.log("arr2",arr2)
//输出:{ '1': [ [ 1, 2, 3 ], [ 1, 5, 9 ] ], '2': [ [ 2, 3, 5 ] ] }
//示例 3:
const arr3=[1,2,3,4,5,6,7,8,9].groupBy(n=>String(n>5))
console.log("arr3",arr3)
//输出:{ "false": [1, 2, 3, 4, 5], "true": [6, 7, 8, 9, 10] }