Skip to content

Commit 0d1ca47

Browse files
committed
feat(dfts-helper): add a_chunk and a_hashFrom
1 parent 5ab78c0 commit 0d1ca47

File tree

5 files changed

+275
-0
lines changed

5 files changed

+275
-0
lines changed

libs/dfts-helper/src/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ export { a_pushIf } from './lib/helper/array/push-if';
2323
export { a_pushIfAbsent } from './lib/helper/array/push-if-absent/push-if-absent';
2424
export { a_remove } from './lib/helper/array/remove/remove';
2525
export { a_removeIf } from './lib/helper/array/remove-if';
26+
export { a_chunk } from './lib/helper/array/chunk/chunk';
2627
export { a_shuffle } from './lib/helper/array/shuffle';
28+
export { a_hashFrom } from './lib/helper/array/hash/hash';
2729

2830
export { b_from } from './lib/helper/boolean/from/from';
2931
export { b_fromStorage } from './lib/helper/boolean/from-storage/from-storage';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
import { a_chunk } from './chunk';
2+
3+
describe('a_chunk', () => {
4+
test('splits an evenly divisible array correctly', () => {
5+
const input = [1, 2, 3, 4, 5, 6];
6+
const result = a_chunk(input, 2);
7+
expect(result).toEqual([
8+
[1, 2],
9+
[3, 4],
10+
[5, 6],
11+
]);
12+
});
13+
14+
test('handles chunk size of 1', () => {
15+
const input = [1, 2, 3];
16+
const result = a_chunk(input, 1);
17+
expect(result).toEqual([[1], [2], [3]]);
18+
});
19+
20+
test('returns empty array when given an empty array', () => {
21+
const input: number[] = [];
22+
const result = a_chunk(input, 2);
23+
expect(result).toEqual([]);
24+
});
25+
26+
test('returns one chunk if chunk size equals the entire array length', () => {
27+
const input = [1, 2, 3, 4];
28+
const result = a_chunk(input, 4);
29+
expect(result).toEqual([[1, 2, 3, 4]]);
30+
});
31+
32+
test('last chunk may be smaller if array length is not divisible by chunk size', () => {
33+
const input = [1, 2, 3, 4, 5];
34+
const result = a_chunk(input, 2);
35+
expect(result).toEqual([[1, 2], [3, 4], [5]]);
36+
});
37+
38+
test('handles chunk size larger than the array length', () => {
39+
const input = [1, 2, 3];
40+
const result = a_chunk(input, 10);
41+
expect(result).toEqual([[1, 2, 3]]);
42+
});
43+
44+
test('works with different data types (strings)', () => {
45+
const input = ['a', 'b', 'c', 'd'];
46+
const result = a_chunk(input, 2);
47+
expect(result).toEqual([
48+
['a', 'b'],
49+
['c', 'd'],
50+
]);
51+
});
52+
53+
test('works with mixed data types', () => {
54+
const input = [1, 'two', { three: 3 }, [4], null];
55+
const result = a_chunk(input, 2);
56+
expect(result).toEqual([[1, 'two'], [{ three: 3 }, [4]], [null]]);
57+
});
58+
59+
test('handles a chunk size of 3', () => {
60+
const input = [1, 2, 3, 4, 5, 6, 7];
61+
const result = a_chunk(input, 3);
62+
expect(result).toEqual([[1, 2, 3], [4, 5, 6], [7]]);
63+
});
64+
65+
test('does not modify the original array', () => {
66+
const input = [1, 2, 3, 4, 5];
67+
const copy = [...input];
68+
a_chunk(input, 2);
69+
expect(input).toEqual(copy);
70+
});
71+
72+
test('handles a large array efficiently', () => {
73+
const input = Array.from({ length: 1000 }, (_, i) => i + 1);
74+
const result = a_chunk(input, 100);
75+
expect(result.length).toBe(10);
76+
expect(result[0].length).toBe(100);
77+
});
78+
79+
test('handles chunk size equal to 2 with odd length input', () => {
80+
const input = [1, 2, 3];
81+
const result = a_chunk(input, 2);
82+
expect(result).toEqual([[1, 2], [3]]);
83+
});
84+
85+
test('handles chunk size equal to the first half of array length', () => {
86+
const input = [1, 2, 3, 4, 5, 6];
87+
const result = a_chunk(input, 3);
88+
expect(result).toEqual([
89+
[1, 2, 3],
90+
[4, 5, 6],
91+
]);
92+
});
93+
94+
test('works with a single-element array', () => {
95+
const input = [42];
96+
const result = a_chunk(input, 5);
97+
expect(result).toEqual([[42]]);
98+
});
99+
100+
test('works with an array of booleans', () => {
101+
const input = [true, false, true, false, true];
102+
const result = a_chunk(input, 2);
103+
expect(result).toEqual([[true, false], [true, false], [true]]);
104+
});
105+
106+
test('works with nested arrays as elements', () => {
107+
const input = [[1], [2], [3], [4]];
108+
const result = a_chunk(input, 2);
109+
expect(result).toEqual([
110+
[[1], [2]],
111+
[[3], [4]],
112+
]);
113+
});
114+
115+
test('handles chunk size of 1 on large input', () => {
116+
const input = [1, 2, 3, 4, 5, 6];
117+
const result = a_chunk(input, 1);
118+
expect(result).toEqual([[1], [2], [3], [4], [5], [6]]);
119+
});
120+
121+
test('returns the input if chunk size is equal to input length', () => {
122+
const input = [10, 20, 30];
123+
const result = a_chunk(input, 3);
124+
expect(result).toEqual([[10, 20, 30]]);
125+
});
126+
127+
test('works with chunk size of 2 on an empty array', () => {
128+
const input: number[] = [];
129+
const result = a_chunk(input, 2);
130+
expect(result).toEqual([]);
131+
});
132+
133+
test('handles large chunk size with large input', () => {
134+
const input = Array.from({ length: 20 }, (_, i) => i + 1);
135+
const result = a_chunk(input, 25);
136+
expect(result).toEqual([input]); // entire array as one chunk
137+
});
138+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export function a_chunk<T>(input: T[], chunkSize: number): T[][] {
2+
const result: T[][] = [];
3+
4+
for (let i = 0; i < input.length; i += chunkSize) {
5+
result.push(input.slice(i, i + chunkSize));
6+
}
7+
8+
return result;
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
import { a_hashFrom } from './hash';
2+
3+
describe('a_hashFrom', () => {
4+
test('returns first element if the string is empty', () => {
5+
const arr = ['a', 'b', 'c'];
6+
expect(a_hashFrom(arr, '')).toBe('a');
7+
});
8+
9+
test('works with a single-character string', () => {
10+
const arr = ['x', 'y', 'z'];
11+
expect(a_hashFrom(arr, 'A')).toBeDefined();
12+
});
13+
14+
test('works with a multi-character string', () => {
15+
const arr = ['apple', 'banana', 'cherry', 'date'];
16+
const result = a_hashFrom(arr, 'hello');
17+
expect(arr).toContain(result);
18+
});
19+
20+
test('returns a consistent value for the same string', () => {
21+
const arr = [1, 2, 3, 4, 5];
22+
const str = 'consistent';
23+
const firstCall = a_hashFrom(arr, str);
24+
const secondCall = a_hashFrom(arr, str);
25+
expect(firstCall).toBe(secondCall);
26+
});
27+
28+
test('different strings should produce different (not necessarily unique) results', () => {
29+
const arr = [1, 2, 3, 4, 5];
30+
const result1 = a_hashFrom(arr, 'abc');
31+
const result2 = a_hashFrom(arr, 'abd');
32+
// They might map to the same index by chance, but often won't.
33+
// This test just ensures the function runs without error.
34+
expect(arr).toContain(result1);
35+
expect(arr).toContain(result2);
36+
});
37+
38+
test('works with non-string array elements (numbers)', () => {
39+
const arr = [10, 20, 30];
40+
const result = a_hashFrom(arr, 'test');
41+
expect([10, 20, 30]).toContain(result);
42+
});
43+
44+
test('works with boolean elements', () => {
45+
const arr = [true, false];
46+
const result = a_hashFrom(arr, 'true-or-false');
47+
expect([true, false]).toContain(result);
48+
});
49+
50+
test('works with objects', () => {
51+
const arr = [{ id: 1 }, { id: 2 }, { id: 3 }];
52+
const result = a_hashFrom(arr, 'object-test');
53+
expect(arr).toContain(result);
54+
});
55+
56+
test('works with large arrays', () => {
57+
const arr = Array.from({ length: 100 }, (_, i) => i);
58+
const result = a_hashFrom(arr, 'large-array');
59+
expect(arr).toContain(result);
60+
});
61+
62+
test('handles special characters in the string', () => {
63+
const arr = ['A', 'B', 'C', 'D'];
64+
const result = a_hashFrom(arr, '✨unicode✨');
65+
expect(arr).toContain(result);
66+
});
67+
68+
test('handles strings that differ by only one character', () => {
69+
const arr = ['red', 'green', 'blue'];
70+
const result1 = a_hashFrom(arr, 'colorA');
71+
const result2 = a_hashFrom(arr, 'colorB');
72+
expect(arr).toContain(result1);
73+
expect(arr).toContain(result2);
74+
// Just ensuring both run without errors and produce valid outputs.
75+
});
76+
77+
test('works with numeric strings', () => {
78+
const arr = [null, 'second', 'third'];
79+
const result = a_hashFrom(arr, '12345');
80+
expect([null, 'second', 'third']).toContain(result);
81+
});
82+
83+
test('works with very long strings', () => {
84+
const arr = ['first', 'second', 'third'];
85+
const longStr = 'a'.repeat(10_000);
86+
const result = a_hashFrom(arr, longStr);
87+
expect(arr).toContain(result);
88+
});
89+
90+
test('works with chunked strings', () => {
91+
const arr = ['first', 'second', 'third', 'fourth'];
92+
const str = 'abcd'.repeat(100); // a repeated pattern
93+
const result = a_hashFrom(arr, str);
94+
expect(arr).toContain(result);
95+
});
96+
97+
test('works with a single-element array', () => {
98+
const arr = [42];
99+
const result = a_hashFrom(arr, 'anything');
100+
expect(result).toBe(42);
101+
});
102+
103+
test('works with a prime-length array', () => {
104+
const arr = [true, false, null, undefined, 0, '', 'end'];
105+
// length: 7 (prime)
106+
const result = a_hashFrom(arr, 'prime-length-test');
107+
expect(arr).toContain(result);
108+
});
109+
110+
test('handles an array of strings with repeated elements', () => {
111+
const arr = ['repeat', 'repeat', 'unique', 'repeat'];
112+
const result = a_hashFrom(arr, 'repetitive');
113+
expect(arr).toContain(result);
114+
});
115+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
export function a_hashFrom<T>(array: T[], str: string): T {
2+
const length = str.length;
3+
if (length === 0) return array[0];
4+
5+
let hash = 0;
6+
for (let i = 0; i < length; i++) {
7+
hash = (hash * 31 + str.charCodeAt(i)) >>> 0;
8+
}
9+
10+
return array[hash % array.length];
11+
}

0 commit comments

Comments
 (0)