From fd7a7c320a67b59d2f19477b595da1ec0d35ca43 Mon Sep 17 00:00:00 2001 From: lionel-rowe Date: Fri, 5 Apr 2024 21:18:59 +0800 Subject: [PATCH] More uses of Object.groupBy --- README.md | 117 ++++++++++++++++++++++++++++++++++++++++++++-- tests/unit/all.js | 74 +++++++++++++++++++++++++++++ 2 files changed, 187 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 90ed30e..596ae32 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,7 @@ For more information, see [Configuring the ESLint Plugin](configuring.md) > objects can easily be converted to an array by use of the > [spread operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax). +1. [_.countBy](#_countBy) 1. [_.each](#_each) 1. [_.every](#_every) 1. [_.filter](#_filter) @@ -120,6 +121,7 @@ For more information, see [Configuring the ESLint Plugin](configuring.md) 1. [_.map](#_map) 1. [_.minBy and _.maxBy](#_minby-and-_maxby) 1. [_.orderBy](#_sortby-and-_orderby) +1. [_.partition](#_partition) 1. [_.pluck](#_pluck) 1. [_.range](#_range) 1. [_.reduce](#_reduce) @@ -204,6 +206,7 @@ For more information, see [Configuring the ESLint Plugin](configuring.md) ### _.chunk Creates an array of elements split into groups the length of size. + ```js // Underscore/Lodash _.chunk(['a', 'b', 'c', 'd'], 2); @@ -212,10 +215,21 @@ _.chunk(['a', 'b', 'c', 'd'], 2); _.chunk(['a', 'b', 'c', 'd'], 3); // => [['a', 'b', 'c'], ['d']] - // Native +function chunk(input, size) { + return Object.values( + Object.groupBy(input, (_, i) => Math.floor(i / size)) + ); +} + +chunk(['a', 'b', 'c', 'd'], 2); +// => [['a', 'b'], ['c', 'd']] + +chunk(['a', 'b', 'c', 'd'], 3); +// => [['a', 'b', 'c'], ['d']] -const chunk = (input, size) => { +// Native #2 (if `Object.groupBy` unavailable) +const chunkReduce = (input, size) => { return input.reduce((arr, item, idx) => { return idx % size === 0 ? [...arr, [item]] @@ -223,13 +237,19 @@ const chunk = (input, size) => { }, []); }; -chunk(['a', 'b', 'c', 'd'], 2); +chunkReduce(['a', 'b', 'c', 'd'], 2); // => [['a', 'b'], ['c', 'd']] -chunk(['a', 'b', 'c', 'd'], 3); +chunkReduce(['a', 'b', 'c', 'd'], 3); // => [['a', 'b', 'c'], ['d']] ``` +#### Browser Support for `Object.groupBy()` + +![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] +:-: | :-: | :-: | :-: | :-: | :-: | + 117.0 ✔ | 117.0 ✔ | 119.0 ✔ | ✖ | 103.0 ✔ | 16.4 ✔ | + #### Browser Support for Spread in array literals ![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] @@ -1198,6 +1218,40 @@ Creates an array of unique values, taking an `iteratee` to compute uniqueness wi > and will not work with objects. If this functionality is needed and no object method is provided, > then Lodash/Underscore is the better option. +### _.countBy + +```js +// Underscore/Lodash +_.countBy([6.1, 4.2, 6.3], Math.floor); +// => { '4': 1, '6': 2 } + +// The `_.property` iteratee shorthand. +_.countBy(['one', 'two', 'three'], 'length'); +// => { '3': 2, '5': 1 } + +// Native +function countBy(input, fn) { + return Object.fromEntries( + Object.entries(Object.groupBy(input, fn)).map(([k, v]) => [k, v.length]) + ); +} + +countBy([6.1, 4.2, 6.3], Math.floor); +// => { '4': 1, '6': 2 } + +// Use explicit callback instead of property name +countBy(['one', 'two', 'three'], (x) => x.length); +// => { '3': 2, '5': 1 } +``` + +#### Browser Support for `Object.groupBy()` + +![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] +:-: | :-: | :-: | :-: | :-: | :-: | + 117.0 ✔ | 117.0 ✔ | 119.0 ✔ | ✖ | 103.0 ✔ | 16.4 ✔ | + +**[⬆ back to top](#quick-links)** + ### _.each Iterates over a list of elements, yielding each in turn to an iteratee function. @@ -1545,6 +1599,61 @@ Extract a functor and use es2015 for better code **[⬆ back to top](#quick-links)** +### _.partition + +```js +// Underscore/Lodash +var users = [ + { 'user': 'barney', 'age': 36, 'active': false }, + { 'user': 'fred', 'age': 40, 'active': true }, + { 'user': 'pebbles', 'age': 1, 'active': false } +]; + +_.partition(users, function (o) { return o.active; }); +// => objects for [['fred'], ['barney', 'pebbles']] + +// The `_.matches` iteratee shorthand. +_.partition(users, { 'age': 1, 'active': false }); +// => objects for [['pebbles'], ['barney', 'fred']] + +// The `_.matchesProperty` iteratee shorthand. +_.partition(users, ['active', false]); +// => objects for [['barney', 'pebbles'], ['fred']] + +// The `_.property` iteratee shorthand. +_.partition(users, 'active'); +// => objects for [['fred'], ['barney', 'pebbles']] + +// Native +function partition(input, fn) { + const results = Object.groupBy(input, (x) => Boolean(fn(x))) + return [results.true ?? [], results.false ?? []] +} + +partition(users, (x) => x.active); +// => objects for [['fred'], ['barney', 'pebbles']] + +// Use explicit callback instead of object partial +partition(users, (x) => x.age === 1 && !x.active); +// => objects for [['pebbles'], ['barney', 'fred']] + +// Use explicit callback instead of [key, val] tuple +partition(users, (x) => !x.active); +// => objects for [['barney', 'pebbles'], ['fred']] + +// Use explicit callback instead of property key +partition(users, (x) => x.active); +// => objects for [['fred'], ['barney', 'pebbles']] +``` + +#### Browser Support for `Object.groupBy()` + +![Chrome][chrome-image] | ![Edge][edge-image] | ![Firefox][firefox-image] | ![IE][ie-image] | ![Opera][opera-image] | ![Safari][safari-image] +:-: | :-: | :-: | :-: | :-: | :-: | + 117.0 ✔ | 117.0 ✔ | 119.0 ✔ | ✖ | 103.0 ✔ | 16.4 ✔ | + +**[⬆ back to top](#quick-links)** + ### _.pluck `array.map` or `_.map` can also be used to replace `_.pluck`. diff --git a/tests/unit/all.js b/tests/unit/all.js index c7875d9..29ad789 100644 --- a/tests/unit/all.js +++ b/tests/unit/all.js @@ -136,6 +136,25 @@ describe('code snippet example', () => { ) }) }) + describe('chunk (Object.groupBy version)', () => { + function chunk(input, size) { + return Object.values( + Object.groupBy(input, (_, i) => Math.floor(i / size)) + ); + } + it("_.chunk(['a', 'b', 'c', 'd'], 2);", () => { + assert.deepEqual( + _.chunk(['a', 'b', 'c', 'd'], 2), + chunk(['a', 'b', 'c', 'd'], 2) + ); + }) + it("_.chunk(['a', 'b', 'c', 'd'], 3);", () => { + assert.deepEqual( + _.chunk(['a', 'b', 'c', 'd'], 3), + chunk(['a', 'b', 'c', 'd'], 3) + ); + }) + }) describe('times', () => { const times = (n, fn = (_, x) => x) => { return Array.from(Array(n), fn) @@ -1098,4 +1117,59 @@ describe('code snippet example', () => { assert.deepEqual(_.head([]), [].at(0)); }); }) + + describe('countBy', () => { + function countBy(input, fn) { + return Object.fromEntries( + Object.entries(Object.groupBy(input, fn)).map(([k, v]) => [k, v.length]) + ); + } + + it('_.countBy([6.1, 4.2, 6.3], Math.floor)', () => { + const lo = _.countBy([6.1, 4.2, 6.3], Math.floor); + const native = countBy([6.1, 4.2, 6.3], Math.floor); + assert.deepEqual(lo, native); + }); + it("_.countBy(['one', 'two', 'three'], 'length')", () => { + const lo = _.countBy(['one', 'two', 'three'], 'length'); + const native = countBy(['one', 'two', 'three'], (x) => x.length); + assert.deepEqual(lo, native); + }); + }); + + describe('partition', () => { + // Underscore/Lodash + var users = [ + { 'user': 'barney', 'age': 36, 'active': false }, + { 'user': 'fred', 'age': 40, 'active': true }, + { 'user': 'pebbles', 'age': 1, 'active': false } + ]; + + function partition(input, fn) { + const results = Object.groupBy(input, (x) => Boolean(fn(x))) + return [results.true ?? [], results.false ?? []] + } + + it("_.partition(users, function (o) { return o.active; });", () => { + const lo = _.partition(users, function (o) { return o.active; }); + const native = partition(users, (x) => x.active); + + assert.deepEqual(lo, native); + }); + it("_.partition(users, { 'age': 1, 'active': false });", () => { + const lo = _.partition(users, { 'age': 1, 'active': false }); + const native = partition(users, (x) => x.age === 1 && !x.active); + assert.deepEqual(lo, native); + }); + it("_.partition(users, ['active', false]);", () => { + const lo = _.partition(users, ['active', false]); + const native = partition(users, (x) => !x.active); + assert.deepEqual(lo, native); + }); + it("_.partition(users, 'active');", () => { + const lo = _.partition(users, 'active'); + const native = partition(users, (x) => x.active); + assert.deepEqual(lo, native); + }); + }) });