Files
aoc/utils/array.test.ts
T
2024-12-08 19:44:46 +01:00

224 lines
6.5 KiB
TypeScript

import { describe, expect, it } from 'bun:test';
import {
combinations,
getMiddleElement,
groupBy,
multArray,
multBy,
replaceChar,
sumArray,
sumBy,
unique
} from './array.ts';
describe('array utils', () => {
it('sumArray number array', () => {
const array = [1, 2, 3];
const sum = sumArray(array);
expect(sum).toBeNumber();
expect(sum).toBeFinite();
expect(sum).toBe(1 + 2 + 3);
expect(sumArray([])).toBeNumber();
expect(sumArray([])).toBeFinite();
expect(sumArray([])).toBe(0);
});
it('sumArray read-only number array', () => {
const array = [1, 2, 3] as const;
const sum = sumArray(array);
expect(sum).toBeNumber();
expect(sum).toBeFinite();
expect(sum).toBe(1 + 2 + 3);
expect(sumArray([])).toBeNumber();
expect(sumArray([])).toBeFinite();
expect(sumArray([])).toBe(0);
});
it('sumBy number array', () => {
const array = [1, 2, 3];
const sum = sumBy(array, (e) => e);
expect(sum).toBeNumber();
expect(sum).toBeFinite();
expect(sum).toBe(1 + 2 + 3);
});
it('sumBy read-only number array', () => {
const array = [1, 2, 3] as const;
const sum = sumBy(array, (e) => e);
expect(sum).toBeNumber();
expect(sum).toBeFinite();
expect(sum).toBe(1 + 2 + 3);
});
it('sumBy mixed array', () => {
const array = [1, '2', 3.1, ''];
const sum = sumBy(array, (e) => e);
expect(sum).toBeNumber();
expect(sum).toBeFinite();
expect(sum).toBe(1 + 2 + 3.1);
});
it('sumBy object array', () => {
const array: (
| { value: number | string }
| { differentValue: number | string }
)[] = [{ value: 3 }, { value: '2' }, { differentValue: '-2.44' }];
const sum = sumBy(array, (e) =>
'differentValue' in e ? e.differentValue : e.value
);
expect(sum).toBeNumber();
expect(sum).toBeFinite();
expect(sum).toBe(3 + 2 - 2.44);
});
it('sumBy empty array', () => {
expect(sumBy([], (e) => e)).toBeNumber();
expect(sumBy([], (e) => e)).toBeFinite();
expect(sumBy([], (e) => e)).toBe(0);
});
it('multArray number array', () => {
const array = [1, 2, 3];
const sum = multArray(array);
expect(sum).toBeNumber();
expect(sum).toBeFinite();
expect(sum).toBe(2 * 3);
expect(multArray([])).toBeNumber();
expect(multArray([])).toBeFinite();
expect(multArray([])).toBe(0);
});
it('multArray read-only number array', () => {
const array = [1, 2, 3] as const;
const sum = multArray(array);
expect(sum).toBeNumber();
expect(sum).toBeFinite();
expect(sum).toBe(2 * 3);
expect(multArray([])).toBeNumber();
expect(multArray([])).toBeFinite();
expect(multArray([])).toBe(0);
});
it('multBy number array', () => {
const array = [1, 2, 3];
const sum = sumBy(array, (e) => e);
expect(sum).toBeNumber();
expect(sum).toBeFinite();
expect(sum).toBe(1 + 2 + 3);
});
it('multBy read-only number array', () => {
const array = [1, 2, 3] as const;
const sum = multBy(array, (e) => e);
expect(sum).toBeNumber();
expect(sum).toBeFinite();
expect(sum).toBe(1 + 2 + 3);
});
it('multBy mixed array', () => {
const array = [1, '2', 3.1, ''];
const sum = multBy(array, (e) => e);
expect(sum).toBeNumber();
expect(sum).toBeFinite();
expect(sum).toBe(0);
});
it('multBy object array', () => {
const array: (
| { value: number | string }
| { differentValue: number | string }
)[] = [{ value: 3 }, { value: '2' }, { differentValue: '-2.44' }];
const sum = multBy(array, (e) =>
'differentValue' in e ? e.differentValue : e.value
);
expect(sum).toBeNumber();
expect(sum).toBeFinite();
expect(sum).toBe(3 * 2 * -2.44);
});
it('multBy empty array', () => {
expect(multBy([], (e) => e)).toBeNumber();
expect(multBy([], (e) => e)).toBeFinite();
expect(multBy([], (e) => e)).toBe(0);
});
it('groupBy', () => {
const arr = [0, 1, 2, 2, 1, 3];
const actual = groupBy(arr, (e) => e);
const expected = [
{ key: 0, elements: [0] },
{ key: 1, elements: [1, 1] },
{ key: 2, elements: [2, 2] },
{ key: 3, elements: [3] }
];
expect(actual).toHaveLength(actual.length);
expect(Object.keys(actual.map((e) => e.key))).toEqual(
expect.arrayContaining(Object.keys(expected.map((e) => e.key)))
);
expected.forEach(({ key, elements }) => {
const actualGroup = actual.find((e) => e.key === key);
expect(actualGroup).toBeTruthy();
expect(actualGroup).toBeObject();
expect(actualGroup?.elements || []).toHaveLength(elements.length);
expect(actualGroup?.elements || []).toEqual(
expect.arrayContaining(elements)
);
});
});
it('getMiddleElement', () => {
expect(getMiddleElement([1, 2, 3, 4])).toBe(3);
expect(getMiddleElement([1, 2, 3])).toBe(2);
expect(getMiddleElement([1])).toBe(1);
expect(getMiddleElement([])).toBeUndefined();
});
it('combinations', () => {
const numbers = [0, 1, 2];
const n = numbers.length;
const actual = combinations(numbers);
const expected = [
{ a: 0, b: 1 },
{ a: 0, b: 2 },
{ a: 1, b: 0 },
{ a: 1, b: 2 },
{ a: 2, b: 0 },
{ a: 2, b: 1 }
];
expect(actual).toHaveLength(n * (n - 1));
expect(actual).toEqual(expect.arrayContaining(expected));
expect(expected).toEqual(expect.arrayContaining(actual));
});
it('unique numbers', () => {
const arr = [0, 1, 2, 2, 1, 3];
const actual = arr.filter(unique());
const expected = [0, 1, 2, 3];
expect(actual).toHaveLength(actual.length);
expect(actual).toEqual(expect.arrayContaining(expected));
expect(expected).toEqual(expect.arrayContaining(actual));
});
it('unique objects', () => {
const arr = [{ a: 0 }, { a: 1 }, { a: 2 }, { a: 2 }, { a: 1 }, { a: 3 }];
const actual = arr.filter(unique((a, b) => a.a === b.a));
const expected = [{ a: 0 }, { a: 1 }, { a: 2 }, { a: 3 }];
expect(actual).toHaveLength(actual.length);
expect(actual).toEqual(expect.arrayContaining(expected));
expect(expected).toEqual(expect.arrayContaining(actual));
// should just pass everything through since objects equality check is by reference
expect(arr.filter(unique())).toHaveLength(arr.length);
});
it('replaceChar', () => {
const input = `000000
111111
222222
333333`;
const rows = input.split('\n');
replaceChar(rows, 1, 2, 'b');
const actual = rows.join('\n');
const expected = `000000
111111
2b2222
333333`;
expect(actual).toHaveLength(expected.length);
expect(actual).toEqual(expected);
});
});