Skip to content

Commit

Permalink
feat(dfts-helper): add a_chunk and a_hashFrom
Browse files Browse the repository at this point in the history
  • Loading branch information
Dafnik committed Dec 13, 2024
1 parent 5ab78c0 commit 0d1ca47
Show file tree
Hide file tree
Showing 5 changed files with 275 additions and 0 deletions.
2 changes: 2 additions & 0 deletions libs/dfts-helper/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ export { a_pushIf } from './lib/helper/array/push-if';
export { a_pushIfAbsent } from './lib/helper/array/push-if-absent/push-if-absent';
export { a_remove } from './lib/helper/array/remove/remove';
export { a_removeIf } from './lib/helper/array/remove-if';
export { a_chunk } from './lib/helper/array/chunk/chunk';
export { a_shuffle } from './lib/helper/array/shuffle';
export { a_hashFrom } from './lib/helper/array/hash/hash';

export { b_from } from './lib/helper/boolean/from/from';
export { b_fromStorage } from './lib/helper/boolean/from-storage/from-storage';
Expand Down
138 changes: 138 additions & 0 deletions libs/dfts-helper/src/lib/helper/array/chunk/chunk.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import { a_chunk } from './chunk';

describe('a_chunk', () => {
test('splits an evenly divisible array correctly', () => {
const input = [1, 2, 3, 4, 5, 6];
const result = a_chunk(input, 2);
expect(result).toEqual([
[1, 2],
[3, 4],
[5, 6],
]);
});

test('handles chunk size of 1', () => {
const input = [1, 2, 3];
const result = a_chunk(input, 1);
expect(result).toEqual([[1], [2], [3]]);
});

test('returns empty array when given an empty array', () => {
const input: number[] = [];
const result = a_chunk(input, 2);
expect(result).toEqual([]);
});

test('returns one chunk if chunk size equals the entire array length', () => {
const input = [1, 2, 3, 4];
const result = a_chunk(input, 4);
expect(result).toEqual([[1, 2, 3, 4]]);
});

test('last chunk may be smaller if array length is not divisible by chunk size', () => {
const input = [1, 2, 3, 4, 5];
const result = a_chunk(input, 2);
expect(result).toEqual([[1, 2], [3, 4], [5]]);
});

test('handles chunk size larger than the array length', () => {
const input = [1, 2, 3];
const result = a_chunk(input, 10);
expect(result).toEqual([[1, 2, 3]]);
});

test('works with different data types (strings)', () => {
const input = ['a', 'b', 'c', 'd'];
const result = a_chunk(input, 2);
expect(result).toEqual([
['a', 'b'],
['c', 'd'],
]);
});

test('works with mixed data types', () => {
const input = [1, 'two', { three: 3 }, [4], null];
const result = a_chunk(input, 2);
expect(result).toEqual([[1, 'two'], [{ three: 3 }, [4]], [null]]);
});

test('handles a chunk size of 3', () => {
const input = [1, 2, 3, 4, 5, 6, 7];
const result = a_chunk(input, 3);
expect(result).toEqual([[1, 2, 3], [4, 5, 6], [7]]);
});

test('does not modify the original array', () => {
const input = [1, 2, 3, 4, 5];
const copy = [...input];
a_chunk(input, 2);
expect(input).toEqual(copy);
});

test('handles a large array efficiently', () => {
const input = Array.from({ length: 1000 }, (_, i) => i + 1);
const result = a_chunk(input, 100);
expect(result.length).toBe(10);
expect(result[0].length).toBe(100);
});

test('handles chunk size equal to 2 with odd length input', () => {
const input = [1, 2, 3];
const result = a_chunk(input, 2);
expect(result).toEqual([[1, 2], [3]]);
});

test('handles chunk size equal to the first half of array length', () => {
const input = [1, 2, 3, 4, 5, 6];
const result = a_chunk(input, 3);
expect(result).toEqual([
[1, 2, 3],
[4, 5, 6],
]);
});

test('works with a single-element array', () => {
const input = [42];
const result = a_chunk(input, 5);
expect(result).toEqual([[42]]);
});

test('works with an array of booleans', () => {
const input = [true, false, true, false, true];
const result = a_chunk(input, 2);
expect(result).toEqual([[true, false], [true, false], [true]]);
});

test('works with nested arrays as elements', () => {
const input = [[1], [2], [3], [4]];
const result = a_chunk(input, 2);
expect(result).toEqual([
[[1], [2]],
[[3], [4]],
]);
});

test('handles chunk size of 1 on large input', () => {
const input = [1, 2, 3, 4, 5, 6];
const result = a_chunk(input, 1);
expect(result).toEqual([[1], [2], [3], [4], [5], [6]]);
});

test('returns the input if chunk size is equal to input length', () => {
const input = [10, 20, 30];
const result = a_chunk(input, 3);
expect(result).toEqual([[10, 20, 30]]);
});

test('works with chunk size of 2 on an empty array', () => {
const input: number[] = [];
const result = a_chunk(input, 2);
expect(result).toEqual([]);
});

test('handles large chunk size with large input', () => {
const input = Array.from({ length: 20 }, (_, i) => i + 1);
const result = a_chunk(input, 25);
expect(result).toEqual([input]); // entire array as one chunk
});
});
9 changes: 9 additions & 0 deletions libs/dfts-helper/src/lib/helper/array/chunk/chunk.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export function a_chunk<T>(input: T[], chunkSize: number): T[][] {
const result: T[][] = [];

for (let i = 0; i < input.length; i += chunkSize) {
result.push(input.slice(i, i + chunkSize));
}

return result;
}
115 changes: 115 additions & 0 deletions libs/dfts-helper/src/lib/helper/array/hash/hash.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { a_hashFrom } from './hash';

describe('a_hashFrom', () => {
test('returns first element if the string is empty', () => {
const arr = ['a', 'b', 'c'];
expect(a_hashFrom(arr, '')).toBe('a');
});

test('works with a single-character string', () => {
const arr = ['x', 'y', 'z'];
expect(a_hashFrom(arr, 'A')).toBeDefined();
});

test('works with a multi-character string', () => {
const arr = ['apple', 'banana', 'cherry', 'date'];
const result = a_hashFrom(arr, 'hello');
expect(arr).toContain(result);
});

test('returns a consistent value for the same string', () => {
const arr = [1, 2, 3, 4, 5];
const str = 'consistent';
const firstCall = a_hashFrom(arr, str);
const secondCall = a_hashFrom(arr, str);
expect(firstCall).toBe(secondCall);
});

test('different strings should produce different (not necessarily unique) results', () => {
const arr = [1, 2, 3, 4, 5];
const result1 = a_hashFrom(arr, 'abc');
const result2 = a_hashFrom(arr, 'abd');
// They might map to the same index by chance, but often won't.
// This test just ensures the function runs without error.
expect(arr).toContain(result1);
expect(arr).toContain(result2);
});

test('works with non-string array elements (numbers)', () => {
const arr = [10, 20, 30];
const result = a_hashFrom(arr, 'test');
expect([10, 20, 30]).toContain(result);
});

test('works with boolean elements', () => {
const arr = [true, false];
const result = a_hashFrom(arr, 'true-or-false');
expect([true, false]).toContain(result);
});

test('works with objects', () => {
const arr = [{ id: 1 }, { id: 2 }, { id: 3 }];
const result = a_hashFrom(arr, 'object-test');
expect(arr).toContain(result);
});

test('works with large arrays', () => {
const arr = Array.from({ length: 100 }, (_, i) => i);
const result = a_hashFrom(arr, 'large-array');
expect(arr).toContain(result);
});

test('handles special characters in the string', () => {
const arr = ['A', 'B', 'C', 'D'];
const result = a_hashFrom(arr, '✨unicode✨');
expect(arr).toContain(result);
});

test('handles strings that differ by only one character', () => {
const arr = ['red', 'green', 'blue'];
const result1 = a_hashFrom(arr, 'colorA');
const result2 = a_hashFrom(arr, 'colorB');
expect(arr).toContain(result1);
expect(arr).toContain(result2);
// Just ensuring both run without errors and produce valid outputs.
});

test('works with numeric strings', () => {
const arr = [null, 'second', 'third'];
const result = a_hashFrom(arr, '12345');
expect([null, 'second', 'third']).toContain(result);
});

test('works with very long strings', () => {
const arr = ['first', 'second', 'third'];
const longStr = 'a'.repeat(10_000);
const result = a_hashFrom(arr, longStr);
expect(arr).toContain(result);
});

test('works with chunked strings', () => {
const arr = ['first', 'second', 'third', 'fourth'];
const str = 'abcd'.repeat(100); // a repeated pattern
const result = a_hashFrom(arr, str);
expect(arr).toContain(result);
});

test('works with a single-element array', () => {
const arr = [42];
const result = a_hashFrom(arr, 'anything');
expect(result).toBe(42);
});

test('works with a prime-length array', () => {
const arr = [true, false, null, undefined, 0, '', 'end'];
// length: 7 (prime)
const result = a_hashFrom(arr, 'prime-length-test');
expect(arr).toContain(result);
});

test('handles an array of strings with repeated elements', () => {
const arr = ['repeat', 'repeat', 'unique', 'repeat'];
const result = a_hashFrom(arr, 'repetitive');
expect(arr).toContain(result);
});
});
11 changes: 11 additions & 0 deletions libs/dfts-helper/src/lib/helper/array/hash/hash.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export function a_hashFrom<T>(array: T[], str: string): T {
const length = str.length;
if (length === 0) return array[0];

let hash = 0;
for (let i = 0; i < length; i++) {
hash = (hash * 31 + str.charCodeAt(i)) >>> 0;
}

return array[hash % array.length];
}

0 comments on commit 0d1ca47

Please sign in to comment.