@gabrielrufino/cerebrum 2.0.7 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Aggregation/GroupBy.js +20 -0
- package/dist/Aggregation/index.js +17 -0
- package/dist/index.js +2 -1
- package/package.json +5 -5
- package/src/Aggregation/GroupBy.spec.ts +129 -0
- package/src/Aggregation/GroupBy.ts +17 -0
- package/src/Aggregation/index.ts +1 -0
- package/src/index.ts +1 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GroupBy = void 0;
|
|
4
|
+
class GroupBy {
|
|
5
|
+
constructor(items, key) {
|
|
6
|
+
this.items = items;
|
|
7
|
+
this.key = key;
|
|
8
|
+
}
|
|
9
|
+
execute() {
|
|
10
|
+
return this.items.reduce((accumulator, item) => {
|
|
11
|
+
const group = item[this.key];
|
|
12
|
+
if (!accumulator[group]) {
|
|
13
|
+
accumulator[group] = [];
|
|
14
|
+
}
|
|
15
|
+
accumulator[group].push(item);
|
|
16
|
+
return accumulator;
|
|
17
|
+
}, {});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
exports.GroupBy = GroupBy;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./GroupBy"), exports);
|
package/dist/index.js
CHANGED
|
@@ -33,7 +33,8 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.Sort = exports.Search = exports.NLP = exports.Math = void 0;
|
|
36
|
+
exports.Sort = exports.Search = exports.NLP = exports.Math = exports.Aggregation = void 0;
|
|
37
|
+
exports.Aggregation = __importStar(require("./Aggregation"));
|
|
37
38
|
exports.Math = __importStar(require("./Math"));
|
|
38
39
|
exports.NLP = __importStar(require("./NLP"));
|
|
39
40
|
exports.Search = __importStar(require("./Search"));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gabrielrufino/cerebrum",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"description": "Algorithms made in TypeScript",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -16,14 +16,14 @@
|
|
|
16
16
|
"author": "Gabriel Rufino <contato@gabrielrufino.com>",
|
|
17
17
|
"license": "UNLICENSED",
|
|
18
18
|
"devDependencies": {
|
|
19
|
-
"@antfu/eslint-config": "^4.
|
|
19
|
+
"@antfu/eslint-config": "^4.19.0",
|
|
20
20
|
"@commitlint/cli": "^19.8.1",
|
|
21
21
|
"@commitlint/config-conventional": "^19.8.1",
|
|
22
22
|
"@faker-js/faker": "^8.4.1",
|
|
23
|
-
"@vitest/coverage-v8": "^3.2.
|
|
24
|
-
"eslint": "^9.
|
|
23
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
24
|
+
"eslint": "^9.32.0",
|
|
25
25
|
"husky": "^9.1.7",
|
|
26
|
-
"typescript": "^5.
|
|
26
|
+
"typescript": "^5.9.2",
|
|
27
27
|
"vitest": "^3.0.5"
|
|
28
28
|
},
|
|
29
29
|
"funding": [
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { GroupBy } from './GroupBy'
|
|
3
|
+
|
|
4
|
+
describe('groupBy', () => {
|
|
5
|
+
interface Person {
|
|
6
|
+
name: string
|
|
7
|
+
age: number
|
|
8
|
+
department: string
|
|
9
|
+
salary: number
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const people: Person[] = [
|
|
13
|
+
{ name: 'Alice', age: 30, department: 'Engineering', salary: 100000 },
|
|
14
|
+
{ name: 'Bob', age: 25, department: 'Engineering', salary: 80000 },
|
|
15
|
+
{ name: 'Charlie', age: 35, department: 'Marketing', salary: 70000 },
|
|
16
|
+
{ name: 'Diana', age: 28, department: 'Marketing', salary: 75000 },
|
|
17
|
+
{ name: 'Eve', age: 32, department: 'Engineering', salary: 90000 },
|
|
18
|
+
{ name: 'Frank', age: 40, department: 'Sales', salary: 85000 },
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
it('should group items by department', () => {
|
|
22
|
+
const groupBy = new GroupBy(people, 'department')
|
|
23
|
+
const result = groupBy.execute()
|
|
24
|
+
|
|
25
|
+
expect(result).toHaveProperty('Engineering')
|
|
26
|
+
expect(result).toHaveProperty('Marketing')
|
|
27
|
+
expect(result).toHaveProperty('Sales')
|
|
28
|
+
|
|
29
|
+
// eslint-disable-next-line dot-notation
|
|
30
|
+
expect(result['Engineering']).toHaveLength(3)
|
|
31
|
+
// eslint-disable-next-line dot-notation
|
|
32
|
+
expect(result['Marketing']).toHaveLength(2)
|
|
33
|
+
// eslint-disable-next-line dot-notation
|
|
34
|
+
expect(result['Sales']).toHaveLength(1)
|
|
35
|
+
|
|
36
|
+
// eslint-disable-next-line dot-notation
|
|
37
|
+
expect(result['Engineering']).toEqual([
|
|
38
|
+
{ name: 'Alice', age: 30, department: 'Engineering', salary: 100000 },
|
|
39
|
+
{ name: 'Bob', age: 25, department: 'Engineering', salary: 80000 },
|
|
40
|
+
{ name: 'Eve', age: 32, department: 'Engineering', salary: 90000 },
|
|
41
|
+
])
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('should group items by age', () => {
|
|
45
|
+
const groupBy = new GroupBy(people, 'age')
|
|
46
|
+
const result = groupBy.execute()
|
|
47
|
+
|
|
48
|
+
expect(result).toHaveProperty('30')
|
|
49
|
+
expect(result).toHaveProperty('25')
|
|
50
|
+
expect(result).toHaveProperty('35')
|
|
51
|
+
expect(result).toHaveProperty('28')
|
|
52
|
+
expect(result).toHaveProperty('32')
|
|
53
|
+
expect(result).toHaveProperty('40')
|
|
54
|
+
|
|
55
|
+
expect(result['30']).toHaveLength(1)
|
|
56
|
+
expect(result['25']).toHaveLength(1)
|
|
57
|
+
expect(result['30'][0]).toEqual({ name: 'Alice', age: 30, department: 'Engineering', salary: 100000 })
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it('should handle empty array', () => {
|
|
61
|
+
const groupBy = new GroupBy([], 'department')
|
|
62
|
+
const result = groupBy.execute()
|
|
63
|
+
|
|
64
|
+
expect(result).toEqual({})
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
it('should handle single item', () => {
|
|
68
|
+
const singlePerson = [{ name: 'John', age: 30, department: 'IT', salary: 50000 }]
|
|
69
|
+
const groupBy = new GroupBy(singlePerson, 'department')
|
|
70
|
+
const result = groupBy.execute()
|
|
71
|
+
|
|
72
|
+
expect(result).toHaveProperty('IT')
|
|
73
|
+
// eslint-disable-next-line dot-notation
|
|
74
|
+
expect(result['IT']).toHaveLength(1)
|
|
75
|
+
// eslint-disable-next-line dot-notation
|
|
76
|
+
expect(result['IT'][0]).toEqual({ name: 'John', age: 30, department: 'IT', salary: 50000 })
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
it('should handle all items having same group key', () => {
|
|
80
|
+
const sameDepartment = [
|
|
81
|
+
{ name: 'Alice', age: 30, department: 'Engineering', salary: 100000 },
|
|
82
|
+
{ name: 'Bob', age: 25, department: 'Engineering', salary: 80000 },
|
|
83
|
+
{ name: 'Charlie', age: 35, department: 'Engineering', salary: 70000 },
|
|
84
|
+
]
|
|
85
|
+
|
|
86
|
+
const groupBy = new GroupBy(sameDepartment, 'department')
|
|
87
|
+
const result = groupBy.execute()
|
|
88
|
+
|
|
89
|
+
expect(result).toHaveProperty('Engineering')
|
|
90
|
+
// eslint-disable-next-line dot-notation
|
|
91
|
+
expect(result['Engineering']).toHaveLength(3)
|
|
92
|
+
expect(Object.keys(result)).toHaveLength(1)
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
it('should work with different data types', () => {
|
|
96
|
+
interface Product {
|
|
97
|
+
id: number
|
|
98
|
+
name: string
|
|
99
|
+
category: string
|
|
100
|
+
inStock: boolean
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const products: Product[] = [
|
|
104
|
+
{ id: 1, name: 'Laptop', category: 'Electronics', inStock: true },
|
|
105
|
+
{ id: 2, name: 'Book', category: 'Education', inStock: false },
|
|
106
|
+
{ id: 3, name: 'Mouse', category: 'Electronics', inStock: true },
|
|
107
|
+
{ id: 4, name: 'Pen', category: 'Education', inStock: true },
|
|
108
|
+
]
|
|
109
|
+
|
|
110
|
+
const groupBy = new GroupBy(products, 'inStock')
|
|
111
|
+
const result = groupBy.execute()
|
|
112
|
+
|
|
113
|
+
expect(result).toHaveProperty('true')
|
|
114
|
+
expect(result).toHaveProperty('false')
|
|
115
|
+
// eslint-disable-next-line dot-notation
|
|
116
|
+
expect(result['true']).toHaveLength(3)
|
|
117
|
+
// eslint-disable-next-line dot-notation
|
|
118
|
+
expect(result['false']).toHaveLength(1)
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
it('should preserve original object references', () => {
|
|
122
|
+
const originalPerson = people[0]
|
|
123
|
+
const groupBy = new GroupBy(people, 'department')
|
|
124
|
+
const result = groupBy.execute()
|
|
125
|
+
|
|
126
|
+
// eslint-disable-next-line dot-notation
|
|
127
|
+
expect(result['Engineering'][0]).toBe(originalPerson)
|
|
128
|
+
})
|
|
129
|
+
})
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export class GroupBy<T extends Record<string, any>> {
|
|
2
|
+
constructor(
|
|
3
|
+
private readonly items: Array<T>,
|
|
4
|
+
private readonly key: keyof T,
|
|
5
|
+
) {}
|
|
6
|
+
|
|
7
|
+
public execute(): Record<string, Array<T>> {
|
|
8
|
+
return this.items.reduce((accumulator, item) => {
|
|
9
|
+
const group = item[this.key]
|
|
10
|
+
if (!accumulator[group]) {
|
|
11
|
+
accumulator[group] = []
|
|
12
|
+
}
|
|
13
|
+
accumulator[group].push(item)
|
|
14
|
+
return accumulator
|
|
15
|
+
}, {} as Record<string, Array<T>>)
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './GroupBy'
|
package/src/index.ts
CHANGED