data-structure-typed
Version:
Standard data structure
980 lines (818 loc) • 28 kB
text/typescript
import { HashMap, LinkedHashMap } from '../../../../src';
import { getRandomInt, getRandomIntArray } from '../../../utils';
describe('HashMap', () => {
let hashMap: HashMap<string, number>;
beforeEach(() => {
hashMap = new HashMap<string, number>();
});
it('should initialize correctly', () => {
expect(hashMap.size).toBe(0);
expect(hashMap.isEmpty()).toBe(true);
});
it('should set and get values', () => {
hashMap.set('one', 1);
hashMap.set('two', 2);
hashMap.set('three', 3);
expect(hashMap.get('one')).toBe(1);
expect(hashMap.get('two')).toBe(2);
expect(hashMap.get('three')).toBe(3);
});
it('should handle key collisions', () => {
// Force a collision by setting two different keys to the same bucket
hashMap.set('key1', 1);
hashMap.set('key2', 2);
expect(hashMap.get('key1')).toBe(1);
expect(hashMap.get('key2')).toBe(2);
});
it('should delete values', () => {
hashMap.set('one', 1);
hashMap.set('two', 2);
hashMap.delete('one');
expect(hashMap.get('one')).toBeUndefined();
expect(hashMap.size).toBe(1);
});
it('should clear the HashMap', () => {
hashMap.set('one', 1);
hashMap.set('two', 2);
hashMap.clear();
expect(hashMap.size).toBe(0);
expect(hashMap.isEmpty()).toBe(true);
});
it('should iterate over entries', () => {
hashMap.set('one', 1);
hashMap.set('two', 2);
hashMap.set('three', 3);
});
it('should resize the table when load factor is exceeded', () => {
// Set a small initial capacity for testing resizing
hashMap = new HashMap<string, number>();
hashMap.set('one', 1);
hashMap.set('two', 2);
hashMap.set('three', 3);
hashMap.set('four', 4); // This should trigger a resize
// expect(hashMap.table.length).toBe(8);
expect(hashMap.get('one')).toBe(1);
expect(hashMap.get('two')).toBe(2);
expect(hashMap.get('three')).toBe(3);
expect(hashMap.get('four')).toBe(4);
});
it('should allow using a custom hash function', () => {
hashMap = new HashMap<string, number>();
hashMap.set('one', 1);
hashMap.set('two', 2);
expect(hashMap.get('one')).toBe(1);
expect(hashMap.get('two')).toBe(2);
// Since the custom hash function always returns 0, these keys will collide.
// Make sure they are stored separately.
// expect(hashMap.table[0].length).toBe(2);
});
it('should clone', () => {
hashMap = new HashMap<string, number>();
hashMap.set('one', 1);
hashMap.set('two', 2);
for (let i = 3; i <= 100; i++) {
hashMap.set(i.toString(), i);
}
expect(hashMap.get('one')).toBe(1);
expect(hashMap.get('two')).toBe(2);
expect(hashMap.get('86')).toBe(86);
expect(hashMap.size).toBe(100);
hashMap.delete('two');
expect(hashMap.size).toBe(99);
const cloned = hashMap.clone();
expect(cloned.get('one')).toBe(1);
expect(cloned.get('two')).toBe(undefined);
expect(cloned.get('86')).toBe(86);
expect(cloned.size).toBe(99);
});
describe('HashMap Test2', () => {
let hashMap: HashMap;
beforeEach(() => {
hashMap = new HashMap();
});
it('should create an empty map', () => {
expect(hashMap.size).toBe(0);
});
it('should add a key-value pair', () => {
hashMap.set('key1', 'value1');
expect(hashMap.get('key1')).toBe('value1');
expect(hashMap.hasValue('value1')).toBe(true);
expect(hashMap.hasValue('value2')).toBe(false);
});
it('should handle object keys correctly', () => {
const keyObj = { id: 1 };
hashMap.set(keyObj, 'objectValue');
expect(hashMap.has(keyObj)).toBe(true);
expect(hashMap.get(keyObj)).toBe('objectValue');
});
it('Inheritability test', () => {
class ExtendedHashMap<K, V> extends HashMap<K, V> {
someOtherParam?: string;
constructor(
elements: Iterable<[K, V]> = [],
options?: {
hashFn?: (key: K) => string;
someOtherParam: string;
}
) {
const { someOtherParam, ...restOptions } = options || {};
super(elements, restOptions);
this.someOtherParam = someOtherParam;
}
}
const eHM = new ExtendedHashMap<string, number>([], {
someOtherParam: 'someOtherParam'
});
eHM.set('one', 1);
expect(eHM.get('one')).toBe(1);
});
it('should raw elements toEntry', () => {
const rawCollection = [
{ id: 1, name: 'item 1' },
{ id: 2, name: 'item 2' }
];
const hm = new HashMap<number, string, { id: number; name: string }>(rawCollection, {
toEntryFn: rawElement => [rawElement.id, rawElement.name]
});
expect(hm.has(1)).toBe(true);
expect(hm.get(2)).toBe('item 2');
expect(hm.size).toBe(2);
});
it('should update the value for an existing key', () => {
hashMap.set('key1', 'value1');
hashMap.set('key1', 'newValue');
expect(hashMap.get('key1')).toBe('newValue');
});
it('should return undefined for a non-existent key', () => {
expect(hashMap.get('nonExistentKey')).toBeUndefined();
});
it('should remove a key-value pair', () => {
hashMap.set('key1', 'value1');
hashMap.delete('key1');
expect(hashMap.get('key1')).toBeUndefined();
});
it('should clear the map', () => {
hashMap.set('key1', 'value1');
expect(hashMap.size).toBe(1);
hashMap.clear();
expect(hashMap.size).toBe(0);
});
it('should iterate over values', () => {
hashMap.set('key1', 'value1');
hashMap.set('key2', 'value2');
const values = [];
for (const value of hashMap) {
values.push(value);
}
expect(values).toEqual([
['key1', 'value1'],
['key2', 'value2']
]);
});
function compareHashMaps(hashMap: HashMap<unknown, unknown>, stdMap: Map<unknown, unknown>) {
expect(hashMap.size).toEqual(stdMap.size);
stdMap.forEach((value, key) => {
expect(hashMap.get(key)).toEqual(value);
});
}
const stdMap: Map<unknown, unknown> = new Map();
const arr: number[] = getRandomIntArray(1000, 1, 10000);
it('delete test', () => {
for (const item of arr) {
stdMap.set(item, item);
hashMap.set(item, item);
}
for (const item of arr) {
if (Math.random() > 0.6) {
expect(hashMap.delete(item)).toEqual(stdMap.delete(item));
}
}
compareHashMaps(hashMap, stdMap);
for (let i = 0; i < 1000; ++i) {
const random = getRandomInt(0, 100);
expect(hashMap.delete(random)).toEqual(stdMap.delete(random));
}
compareHashMaps(hashMap, stdMap);
});
});
describe('HashMap for coordinate object keys', () => {
const hashMap: HashMap<[number, number], number> = new HashMap();
const codObjs: [number, number][] = [];
for (let i = 0; i < 10; i++) {
const codObj: [number, number] = [getRandomInt(-10000, 10000), i];
codObjs.push(codObj);
}
it('set elements in hash map', () => {
for (let i = 0; i < codObjs.length; i++) {
const codObj = codObjs[i];
hashMap.set(codObj, i);
}
});
it('get elements in hash map', () => {
for (let i = 0; i < codObjs.length; i++) {
const codObj = codObjs[i];
if (codObj) {
expect(hashMap.get(codObj)).toBe(i);
}
}
});
it('should spread elements in hash map', () => {
expect([...hashMap]).toEqual(codObjs.map(codObj => [codObj, codObj[1]]));
});
it('delete elements in hash map', () => {
for (let i = 0; i < 10; i++) {
if (i === 500) expect(hashMap.size).toBe(500);
const codObj = codObjs[i];
if (codObj) hashMap.delete(codObj);
}
expect(hashMap.size).toBe(0);
});
});
describe('HashMap setMany, keys, values', () => {
const hm: HashMap<number, number> = new HashMap<number, number>();
beforeEach(() => {
hm.clear();
hm.setMany([
[2, 2],
[3, 3],
[4, 4],
[5, 5]
]);
hm.setMany([
[2, 2],
[3, 3],
[4, 4],
[6, 6]
]);
});
it('keys', () => {
expect([...hm.keys()]).toEqual([2, 3, 4, 5, 6]);
});
it('values', () => {
expect([...hm.values()]).toEqual([2, 3, 4, 5, 6]);
});
it('print', () => {
expect(hm.toVisual()).toEqual([
[2, 2],
[3, 3],
[4, 4],
[5, 5],
[6, 6]
]);
});
});
describe('HashMap HOF', () => {
let hashMap: HashMap<string, string>;
beforeEach(() => {
hashMap = new HashMap<string, string>();
hashMap.set('key1', 'value1');
hashMap.set('key2', 'value2');
hashMap.set('key3', 'value3');
});
it('every() returns true if all elements match the condition', () => {
expect(hashMap.every(value => typeof value === 'string')).toBe(true);
});
it('some() returns true if any element matches the condition', () => {
expect(hashMap.some(key => key === 'key1')).toBe(true);
});
it('forEach() should execute a function for each element', () => {
const mockCallback = jest.fn();
hashMap.forEach(mockCallback);
expect(mockCallback.mock.calls.length).toBe(3);
});
it('map() should transform each element', () => {
const newHashMap = hashMap.map((key, value) => value.toUpperCase());
expect(newHashMap.get('key1')).toBe('VALUE1');
});
it('filter() should remove elements that do not match the condition', () => {
const filteredHashMap = hashMap.filter(key => key !== 'key1');
expect(filteredHashMap.has('key1')).toBe(false);
});
it('reduce() should accumulate values', () => {
const result = hashMap.reduce((acc, value) => acc + value, '');
expect(result).toBe('value1value2value3');
});
it('should spread in an array', () => {
expect([...hashMap]).toEqual([
['key1', 'value1'],
['key2', 'value2'],
['key3', 'value3']
]);
});
it('should find', () => {
const found = hashMap.find((key, value) => value === 'value1');
expect(found).toEqual(['key1', 'value1']);
const notFound = hashMap.find(value => value === 'value6');
expect(notFound).toEqual(undefined);
});
it('should every', () => {
const isEvery = hashMap.every((key, value) => value.substring(0, 5) === 'value');
expect(isEvery).toEqual(true);
const isEvery4 = hashMap.every((key, value) => value.substring(0, 4) === 'value');
expect(isEvery4).toEqual(false);
});
it('should some', () => {
const isSome = hashMap.some((key, value) => value.substring(5, 6) === '2');
expect(isSome).toEqual(true);
const isSome4 = hashMap.some((key, value) => value.substring(0, 5) === 'value');
expect(isSome4).toEqual(true);
});
it('should forEach', () => {
hashMap.forEach((key, value, index) => expect(value.substring(5, 6)).toBe(String(index + 1)));
});
it('should entries', () => {
const entries = hashMap.entries();
expect(entries.next()).toEqual({ done: false, value: ['key1', 'value1'] });
expect(entries.next()).toEqual({ done: false, value: ['key2', 'value2'] });
expect(entries.next()).toEqual({ done: false, value: ['key3', 'value3'] });
expect(entries.next()).toEqual({ done: true, value: undefined });
});
it('should keys', () => {
const keys = hashMap.keys();
expect(keys.next()).toEqual({ done: false, value: 'key1' });
expect(keys.next()).toEqual({ done: false, value: 'key2' });
expect(keys.next()).toEqual({ done: false, value: 'key3' });
expect(keys.next()).toEqual({ done: true, value: undefined });
});
it('should values', () => {
const values = hashMap.values();
expect(values.next()).toEqual({ done: false, value: 'value1' });
expect(values.next()).toEqual({ done: false, value: 'value2' });
expect(values.next()).toEqual({ done: false, value: 'value3' });
expect(values.next()).toEqual({ done: true, value: undefined });
});
});
});
describe('LinkedHashMap', () => {
let hashMap: LinkedHashMap;
beforeEach(() => {
hashMap = new LinkedHashMap();
});
it('should create an empty map', () => {
expect(hashMap.size).toBe(0);
});
it('should add a key-value pair', () => {
expect(hashMap.first).toBe(undefined);
hashMap.set('key1', 'value1');
expect(hashMap.get('key1')).toBe('value1');
});
it('should handle object keys correctly', () => {
const keyObj = { id: 1 };
hashMap.set(keyObj, 'objectValue');
expect(hashMap.get(keyObj)).toBe('objectValue');
});
it('should handle number keys correctly', () => {
hashMap.set(999, { a: '999Value' });
expect(hashMap.get(999)).toEqual({
a: '999Value'
});
});
it('should update the value for an existing key', () => {
hashMap.set('key1', 'value1');
hashMap.set('key1', 'newValue');
expect(hashMap.get('key1')).toBe('newValue');
});
it('should return undefined for a non-existent key', () => {
expect(hashMap.get('nonExistentKey')).toBeUndefined();
});
it('should remove a key-value pair', () => {
hashMap.set('key1', 'value1');
hashMap.delete('key1');
expect(hashMap.get('key1')).toBeUndefined();
});
it('should clear the map', () => {
hashMap.set('key1', 'value1');
expect(hashMap.size).toBe(1);
hashMap.clear();
expect(hashMap.size).toBe(0);
});
it('should iterate over values', () => {
hashMap.set('key1', 'value1');
hashMap.set('key2', 'value2');
const values = [];
for (const value of hashMap) {
values.push(value);
}
expect(values).toEqual([
['key1', 'value1'],
['key2', 'value2']
]);
});
function compareHashMaps(hashMap: LinkedHashMap<unknown, unknown>, stdMap: Map<unknown, unknown>) {
expect(hashMap.size).toEqual(stdMap.size);
let index = 0;
stdMap.forEach((value, key) => {
if (index === 0) {
expect(hashMap.first).toEqual([key, value]);
expect(hashMap.begin().next().value).toEqual([key, value]);
} else if (index === hashMap.size - 1) {
expect(hashMap.last).toEqual([key, value]);
expect(hashMap.reverseBegin().next().value).toEqual([key, value]);
} else if (index <= 1000) {
expect(hashMap.at(index)).toBe(value);
}
expect(hashMap.get(key)).toEqual(value);
index++;
});
}
const stdMap: Map<unknown, unknown> = new Map();
const arr: number[] = getRandomIntArray(1000, 1, 10000);
it('delete test', () => {
for (const item of arr) {
stdMap.set(item, item);
hashMap.set(item, item);
}
for (const item of arr) {
if (Math.random() > 0.6) {
expect(hashMap.delete(item)).toEqual(stdMap.delete(item));
}
}
compareHashMaps(hashMap, stdMap);
for (let i = 0; i < 1000; ++i) {
const random = getRandomInt(0, 100);
expect(hashMap.delete(random)).toEqual(stdMap.delete(random));
}
compareHashMaps(hashMap, stdMap);
});
it('should iterate correctly with reverse iterators', () => {
hashMap.set('key1', 'value1');
hashMap.set('key2', 'value2');
const iterator = hashMap.reverseBegin();
expect(iterator.next().value).toEqual(['key2', 'value2']);
});
it('should return the last element', () => {
hashMap.set('key1', 'value1');
hashMap.set('key2', 'value2');
expect(hashMap.last).toEqual(['key2', 'value2']);
});
it('should return undefined for empty map', () => {
expect(hashMap.last).toBeUndefined();
});
it('should get element at specific index', () => {
hashMap.set('key1', 'value1');
hashMap.set('key2', 'value2');
expect(hashMap.at(1)).toBe('value2');
});
it('should hashFn, objHashFn, toEntryFn work well', () => {
const data: Array<{ name: number }> = [{ name: 1 }, { name: 2 }, { name: 3 }];
const hm = new LinkedHashMap(data, {
hashFn: key => String(key),
objHashFn: obj => obj,
toEntryFn: ({ name }) => [{ name }, name]
});
expect(hm.hashFn).toBeTruthy();
expect(hm.objHashFn).toBeTruthy();
expect(hm.toEntryFn).toBeTruthy();
expect([...hm]).toEqual([
[{ name: 1 }, 1],
[{ name: 2 }, 2],
[{ name: 3 }, 3]
]);
});
it('should begin, reverseBegin', () => {
const data: Array<{ name: number }> = [{ name: 1 }, { name: 2 }, { name: 3 }];
const hm = new LinkedHashMap(data, {
hashFn: key => String(key),
objHashFn: obj => obj,
toEntryFn: ({ name }) => [{ name }, name]
});
expect(hm.begin().next()).toEqual({
done: false,
value: [
{
name: 1
},
1
]
});
expect(hm.reverseBegin().next()).toEqual({
done: false,
value: [
{
name: 3
},
3
]
});
});
it('should clone', () => {
hashMap = new LinkedHashMap<string, number>();
hashMap.set('one', 1);
hashMap.set('two', 2);
for (let i = 3; i <= 100; i++) {
hashMap.set(i.toString(), i);
}
expect(hashMap.get('one')).toBe(1);
expect(hashMap.get('two')).toBe(2);
expect(hashMap.get('86')).toBe(86);
expect(hashMap.size).toBe(100);
hashMap.delete('two');
expect(hashMap.size).toBe(99);
const cloned = hashMap.clone();
expect(cloned.get('one')).toBe(1);
expect(cloned.get('two')).toBe(undefined);
expect(cloned.get('86')).toBe(86);
expect(cloned.size).toBe(99);
});
describe('LinkedHashMap basic', () => {
let hashMap: LinkedHashMap<string, number>;
beforeEach(() => {
hashMap = new LinkedHashMap<string, number>();
});
it('should initialize correctly', () => {
expect(hashMap.size).toBe(0);
// expect(hashMap.table.length).toBe(16);
// expect(hashMap.loadFactor).toBe(0.75);
// expect(hashMap.capacityMultiplier).toBe(2);
// expect(hashMap.initialCapacity).toBe(16);
expect(hashMap.isEmpty()).toBe(true);
});
it('should put and get values', () => {
hashMap.set('one', 1);
hashMap.set('two', 2);
hashMap.set('three', 3);
expect(hashMap.get('one')).toBe(1);
expect(hashMap.get('two')).toBe(2);
expect(hashMap.get('three')).toBe(3);
});
it('should handle key collisions', () => {
// Force a collision by setting two different keys to the same bucket
hashMap.set('key1', 1);
hashMap.set('key2', 2);
expect(hashMap.get('key1')).toBe(1);
expect(hashMap.get('key2')).toBe(2);
});
it('should delete values', () => {
hashMap.set('one', 1);
hashMap.set('two', 2);
hashMap.delete('one');
expect(hashMap.get('one')).toBeUndefined();
expect(hashMap.size).toBe(1);
hashMap.deleteAt(0);
// expect(hashMap.get('two')).toBe(undefined); // TODO #99
expect(hashMap.size).toBe(0);
});
it('should clear the LinkedHashMap', () => {
hashMap.set('one', 1);
hashMap.set('two', 2);
hashMap.clear();
expect(hashMap.size).toBe(0);
expect(hashMap.isEmpty()).toBe(true);
});
it('should iterate over entries', () => {
hashMap.set('one', 1);
hashMap.set('two', 2);
hashMap.set('three', 3);
// const entries = Array.from(hashMap.entries());
// expect(entries).toContainEqual(['one', 1]);
// expect(entries).toContainEqual(['two', 2]);
// expect(entries).toContainEqual(['three', 3]);
});
it('should resize the table when load factor is exceeded', () => {
// Set a small initial capacity for testing resizing
hashMap = new LinkedHashMap<string, number>();
hashMap.set('one', 1);
hashMap.set('two', 2);
hashMap.set('three', 3);
hashMap.set('four', 4); // This should trigger a resize
// expect(hashMap.table.length).toBe(8);
expect(hashMap.get('one')).toBe(1);
expect(hashMap.get('two')).toBe(2);
expect(hashMap.get('three')).toBe(3);
expect(hashMap.get('four')).toBe(4);
});
it('should allow using a custom hash function', () => {
hashMap = new LinkedHashMap<string, number>();
hashMap.set('one', 1);
hashMap.set('two', 2);
expect(hashMap.get('one')).toBe(1);
expect(hashMap.get('two')).toBe(2);
// Since the custom hash function always returns 0, these keys will collide.
// Make sure they are stored separately.
// expect(hashMap.table[0].length).toBe(2);
});
// it('should handle number keys correctly', () => {
// const hm = new LinkedHashMap();
// hm.set(999, { a: '999Value' });
// hm.set('999', {a: '999StrValue'})
// expect(hm.get(999)).toEqual({ a: '999Value' });
// expect(hm.get('999')).toEqual({ a: '999StrValue1' });
// });
});
describe('coordinate object keys', () => {
const hashMap: LinkedHashMap<[number, number], number> = new LinkedHashMap();
const codObjs: [number, number][] = [];
it('set elements in hash map', () => {
for (let i = 0; i < 1000; i++) {
const codObj: [number, number] = [getRandomInt(-10000, 10000), i];
codObjs.push(codObj);
hashMap.set(codObj, i);
}
});
it('get elements in hash map', () => {
for (let i = 0; i < 1000; i++) {
const codObj = codObjs[i];
if (codObj) {
expect(hashMap.get(codObj)).toBe(i);
}
}
});
it('delete elements in hash map', () => {
for (let i = 0; i < 1000; i++) {
if (i === 500) expect(hashMap.size).toBe(500);
const codObj = codObjs[i];
if (codObj) hashMap.delete(codObj);
}
expect(hashMap.size).toBe(0);
});
});
describe('setMany, keys, values', () => {
const hm: LinkedHashMap<number, number> = new LinkedHashMap<number, number>();
beforeEach(() => {
hm.clear();
hm.setMany([
[2, 2],
[3, 3],
[4, 4],
[5, 5]
]);
hm.setMany([
[2, 2],
[3, 3],
[4, 4],
[6, 6]
]);
});
it('keys', () => {
expect([...hm.keys()]).toEqual([2, 3, 4, 5, 6]);
});
it('values', () => {
expect([...hm.values()]).toEqual([2, 3, 4, 5, 6]);
});
it('entries', () => {
expect([...hm.entries()]).toEqual([
[2, 2],
[3, 3],
[4, 4],
[5, 5],
[6, 6]
]);
});
it('every', () => {
expect(hm.every(value => value > 4)).toBe(false);
});
it('some', () => {
expect(hm.some(value => value > 6)).toBe(false);
});
it('hasValue', () => {
expect(hm.hasValue(3)).toBe(true);
expect(hm.hasValue(7)).toBe(false);
});
it('print', () => {
// hm.print();
});
});
describe('HashMap HOF', () => {
let hashMap: LinkedHashMap;
beforeEach(() => {
hashMap = new LinkedHashMap<string, string>();
hashMap.set('key1', 'value1');
hashMap.set('key2', 'value2');
hashMap.set('key3', 'value3');
});
it('every() returns true if all elements match the condition', () => {
expect(hashMap.every(value => typeof value === 'string')).toBe(true);
});
it('some() returns true if any element matches the condition', () => {
expect(hashMap.some(key => key === 'key1')).toBe(true);
});
it('forEach() should execute a function for each element', () => {
const mockCallback = jest.fn();
hashMap.forEach(mockCallback);
expect(mockCallback.mock.calls.length).toBe(3);
});
it('map() should transform each element', () => {
const newHashMap = hashMap.map((key, value) => [key, value.toUpperCase()]);
expect(newHashMap.get('key1')).toBe('VALUE1');
});
it('filter() should remove elements that do not match the condition', () => {
const filteredHashMap = hashMap.filter(key => key !== 'key1');
expect(filteredHashMap.has('key1')).toBe(false);
});
it('reduce() should accumulate values', () => {
const result = hashMap.reduce((acc, value) => acc + value, '');
expect(result).toBe('value1value2value3');
});
});
});
describe('classic uses', () => {
it('@example should maintain insertion order', () => {
const linkedHashMap = new LinkedHashMap<number, string>();
linkedHashMap.set(1, 'A');
linkedHashMap.set(2, 'B');
linkedHashMap.set(3, 'C');
const result = Array.from(linkedHashMap);
expect(result).toEqual([
[1, 'A'],
[2, 'B'],
[3, 'C']
]);
});
it('should allow reverse iteration', () => {
const linkedHashMap = new LinkedHashMap<number, string>();
linkedHashMap.set(1, 'A');
linkedHashMap.set(2, 'B');
linkedHashMap.set(3, 'C');
const result = Array.from(linkedHashMap.reverseBegin());
expect(result).toEqual([
[3, 'C'],
[2, 'B'],
[1, 'A']
]);
});
it('should allow fast deletion at an index', () => {
const linkedHashMap = new LinkedHashMap<number, string>();
linkedHashMap.set(1, 'A');
linkedHashMap.set(2, 'B');
linkedHashMap.set(3, 'C');
linkedHashMap.deleteAt(1);
const result = Array.from(linkedHashMap);
expect(result).toEqual([
[1, 'A'],
[3, 'C']
]);
});
it('should filter entries correctly', () => {
const linkedHashMap = new LinkedHashMap<number, string>();
linkedHashMap.set(1, 'A');
linkedHashMap.set(2, 'B');
linkedHashMap.set(3, 'C');
const filteredMap = linkedHashMap.filter((key, value) => value !== 'B');
const result = Array.from(filteredMap);
expect(result).toEqual([
[1, 'A'],
[3, 'C']
]);
});
it('should map entries to a new LinkedHashMap', () => {
const linkedHashMap = new LinkedHashMap<number, string>();
linkedHashMap.set(1, 'A');
linkedHashMap.set(2, 'B');
const mappedMap = linkedHashMap.map((key, value) => [value, key]);
const result = Array.from(mappedMap);
expect(result).toEqual([
['A', 1],
['B', 2]
]);
});
});
describe('classic uses', () => {
it('@example fast lookup of values by key', () => {
const hashMap = new HashMap<number, string>();
hashMap.set(1, 'A');
hashMap.set(2, 'B');
hashMap.set(3, 'C');
expect(hashMap.get(1)).toBe('A');
expect(hashMap.get(2)).toBe('B');
expect(hashMap.get(3)).toBe('C');
expect(hashMap.get(99)).toBeUndefined(); // Key not present
});
it('@example remove duplicates when adding multiple entries', () => {
const hashMap = new HashMap<number, string>();
hashMap.set(1, 'A');
hashMap.set(2, 'B');
hashMap.set(1, 'C'); // Update value for key 1
expect(hashMap.size).toBe(2);
expect(hashMap.get(1)).toBe('C');
expect(hashMap.get(2)).toBe('B');
});
it('@example count occurrences of keys', () => {
const data = [1, 2, 1, 3, 2, 1];
const countMap = new HashMap<number, number>();
for (const key of data) {
countMap.set(key, (countMap.get(key) || 0) + 1);
}
expect(countMap.get(1)).toBe(3);
expect(countMap.get(2)).toBe(2);
expect(countMap.get(3)).toBe(1);
});
it('should group entries by a key-derived property', () => {
const entries = [
{ id: 1, group: 'A' },
{ id: 2, group: 'B' },
{ id: 3, group: 'A' },
{ id: 4, group: 'B' }
];
const groupedMap = new HashMap<string, number[]>();
for (const entry of entries) {
const group = entry.group;
const id = entry.id;
if (!groupedMap.has(group)) {
groupedMap.set(group, []);
}
groupedMap.get(group)?.push(id);
}
expect(groupedMap.get('A')).toEqual([1, 3]);
expect(groupedMap.get('B')).toEqual([2, 4]);
});
});