refactor: Eliminate unnecessary data structures. test: Add performance comparison tests with native Map and Set.

This commit is contained in:
Revone 2023-11-20 09:51:34 +08:00
parent b7357def44
commit 1e2013df5e
12 changed files with 109 additions and 264 deletions

View file

@ -8,7 +8,7 @@ All notable changes to this project will be documented in this file.
- [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
- [`auto-changelog`](https://github.com/CookPete/auto-changelog)
## [v1.46.2](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming)
## [v1.46.3](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming)
### Changes

View file

@ -1,63 +0,0 @@
/**
* data-structure-typed
*
* @author Tyler Zeng
* @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
* @license MIT License
*/
export class CoordinateMap<V> extends Map<any, V> {
constructor(joint?: string) {
super();
if (joint !== undefined) this._joint = joint;
}
protected _joint = '_';
get joint(): string {
return this._joint;
}
/**
* The "has" function overrides the base class's "has" function and checks if a key exists in the map by joining the
* key array with a specified delimiter.
* @param {number[]} key - The parameter "key" is an array of numbers.
* @returns The `has` method is being overridden to return the result of calling the `has` method of the superclass
* (`super.has`) with the `key` array joined together using the `_joint` property.
*/
override has(key: number[]) {
return super.has(key.join(this._joint));
}
/**
* The function overrides the set method of a Map object to convert the key from an array to a string using a specified
* delimiter before calling the original set method.
* @param {number[]} key - The key parameter is an array of numbers.
* @param {V} value - The value parameter is the value that you want to associate with the specified key.
* @returns The `set` method is returning the result of calling the `set` method of the superclass
* (`super.set(key.join(this._joint), value)`).
*/
override set(key: number[], value: V) {
return super.set(key.join(this._joint), value);
}
/**
* The function overrides the get method to join the key array with a specified joint and then calls the super get
* method.
* @param {number[]} key - An array of numbers
* @returns The code is returning the value associated with the specified key in the map.
*/
override get(key: number[]) {
return super.get(key.join(this._joint));
}
/**
* The function overrides the delete method and joins the key array using a specified joint character before calling
* the super delete method.
* @param {number[]} key - An array of numbers that represents the key to be deleted.
* @returns The `delete` method is returning the result of calling the `delete` method on the superclass, with the
* `key` array joined together using the `_joint` property.
*/
override delete(key: number[]) {
return super.delete(key.join(this._joint));
}
}

View file

@ -1,52 +0,0 @@
/**
* data-structure-typed
*
* @author Tyler Zeng
* @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
* @license MIT License
*/
export class CoordinateSet extends Set<any> {
constructor(joint?: string) {
super();
if (joint !== undefined) this._joint = joint;
}
protected _joint = '_';
get joint(): string {
return this._joint;
}
/**
* The "has" function overrides the "has" method of the superclass and checks if a value exists in an array after
* joining its elements with a specified separator.
* @param {number[]} value - The parameter "value" is an array of numbers.
* @returns The overridden `has` method is returning the result of calling the `has` method of the superclass, passing
* in the joined value as an argument.
*/
override has(value: number[]) {
return super.has(value.join(this._joint));
}
/**
* The "add" function overrides the parent class's "add" function by joining the elements of the input array with a
* specified delimiter before calling the parent class's "add" function.
* @param {number[]} value - An array of numbers
* @returns The overridden `add` method is returning the result of calling the `add` method of the superclass
* (`super.add`) with the joined string representation of the `value` array (`value.join(this._joint)`).
*/
override add(value: number[]) {
return super.add(value.join(this._joint));
}
/**
* The function overrides the delete method and deletes an element from a Set by joining the elements of the input
* array with a specified joint and then calling the delete method of the parent class.
* @param {number[]} value - An array of numbers
* @returns The `delete` method is returning the result of calling the `delete` method of the superclass, with the
* `value` array joined together using the `_joint` property.
*/
override delete(value: number[]) {
return super.delete(value.join(this._joint));
}
}

View file

@ -1,6 +1,2 @@
export * from './hash-table';
export * from './coordinate-map';
export * from './coordinate-set';
export * from './tree-map';
export * from './tree-set';
export * from './hash-map';

View file

@ -1,2 +0,0 @@
export class TreeMap {
}

View file

@ -1,2 +0,0 @@
export class TreeSet {
}

View file

@ -23,6 +23,7 @@ if (isCompetitor) {
}
});
}
suite.add(`${MILLION.toLocaleString()} set & get`, () => {
const hm = new HashMap<number, number>();
@ -33,6 +34,41 @@ suite.add(`${MILLION.toLocaleString()} set & get`, () => {
hm.get(i);
}
});
suite.add(`${MILLION.toLocaleString()} Map set & get`, () => {
const hm = new Map<number, number>();
for (let i = 0; i < MILLION; i++) {
hm.set(i, i);
}
for (let i = 0; i < MILLION; i++) {
hm.get(i);
}
});
suite.add(`${MILLION.toLocaleString()} Map set`, () => {
const hm = new Map<number, number>();
for (let i = 0; i < MILLION; i++) hm.set(i, i);
});
suite.add(`${MILLION.toLocaleString()} Set add`, () => {
const hs = new Set<number>();
for (let i = 0; i < MILLION; i++) hs.add(i);
});
suite.add(`${MILLION.toLocaleString()} Set add & has`, () => {
const hs = new Set<number>();
for (let i = 0; i < MILLION; i++) {
hs.add(i);
}
for (let i = 0; i < MILLION; i++) {
hs.has(i);
}
});
if (isCompetitor) {
suite.add(`${MILLION.toLocaleString()} CPT set & get`, () => {
const hm = new CHashMap<number, number>();
@ -45,4 +81,44 @@ if (isCompetitor) {
}
});
}
suite.add(`${MILLION.toLocaleString()} ObjKey set & get`, () => {
const hm = new HashMap<[number, number], number>();
const objKeys:[number, number][] = [];
for (let i = 0; i < MILLION; i++) {
const obj: [number, number] = [i, i];
objKeys.push(obj)
hm.set(obj, i);
}
for (let i = 0; i < MILLION; i++) {
hm.get(objKeys[i]);
}
});
suite.add(`${MILLION.toLocaleString()} Map ObjKey set & get`, () => {
const hm = new Map<[number, number], number>();
const objs:[number, number][] = [];
for (let i = 0; i < MILLION; i++) {
const obj: [number, number] = [i, i];
objs.push(obj)
hm.set(obj, i);
}
for (let i = 0; i < MILLION; i++) {
hm.get(objs[i]);
}
});
suite.add(`${MILLION.toLocaleString()} Set ObjKey add & has`, () => {
const hs = new Set<[number, number]>();
const objs:[number, number][] = [];
for (let i = 0; i < MILLION; i++) {
const obj: [number, number] = [i, i];
objs.push(obj)
hs.add(obj);
}
for (let i = 0; i < MILLION; i++) {
hs.has(objs[i]);
}
});
export { suite };

View file

@ -1,74 +0,0 @@
import { CoordinateMap } from '../../../../src';
describe('CoordinateMap', () => {
it('should set and get values correctly', () => {
const coordinateMap = new CoordinateMap<string>();
const key = [1, 2, 3];
const value = 'TestValue';
coordinateMap.set(key, value);
const retrievedValue = coordinateMap.get(key);
expect(retrievedValue).toBe(value);
});
it('should return true when key exists', () => {
const coordinateMap = new CoordinateMap<string>();
const key = [1, 2, 3];
const value = 'TestValue';
coordinateMap.set(key, value);
expect(coordinateMap.has(key)).toBe(true);
});
it('should return false when key does not exist', () => {
const coordinateMap = new CoordinateMap<string>();
const key = [1, 2, 3];
expect(coordinateMap.has(key)).toBe(false);
});
it('should delete key-value pair correctly', () => {
const coordinateMap = new CoordinateMap<string>();
const key = [1, 2, 3];
const value = 'TestValue';
coordinateMap.set(key, value);
coordinateMap.delete(key);
expect(coordinateMap.has(key)).toBe(false);
});
it('should allow changing the joint character', () => {
const coordinateMap = new CoordinateMap<string>();
const key = [1, 2, 3];
const value = 'TestValue';
coordinateMap.set(key, value);
const newKey = [1, 2, 3];
const retrievedValue = coordinateMap.get(newKey);
expect(retrievedValue).toBe(value);
});
});
describe('CoordinateMap', () => {
class MyCoordinateMap<V = any> extends CoordinateMap<V> {
constructor(joint?: string) {
super(joint);
this._joint = joint += '-';
}
}
const cMap = new MyCoordinateMap<number>('*');
beforeEach(() => {
cMap.set([0, 0], 0);
cMap.set([0, 1], 1);
cMap.set([1, 1], 11);
});
it('should joint to be *-', () => {
expect(cMap.joint).toBe('*-');
});
});

View file

@ -1,66 +0,0 @@
import { CoordinateSet } from '../../../../src';
describe('CoordinateSet', () => {
it('should add and check values correctly', () => {
const coordinateSet = new CoordinateSet();
const value = [1, 2, 3];
coordinateSet.add(value);
const hasValue = coordinateSet.has(value);
expect(hasValue).toBe(true);
});
it('should return false when value does not exist', () => {
const coordinateSet = new CoordinateSet();
const value = [1, 2, 3];
expect(coordinateSet.has(value)).toBe(false);
});
it('should delete value correctly', () => {
const coordinateSet = new CoordinateSet();
const value = [1, 2, 3];
coordinateSet.add(value);
coordinateSet.delete(value);
expect(coordinateSet.has(value)).toBe(false);
});
it('should allow changing the joint character', () => {
const coordinateSet = new CoordinateSet();
const value = [1, 2, 3];
coordinateSet.add(value);
const newValue = [1, 2, 3];
const hasValue = coordinateSet.has(newValue);
expect(hasValue).toBe(true);
});
});
describe('MyCoordinateSet', () => {
class MyCoordinateSet extends CoordinateSet {
constructor(joint?: string) {
super(joint);
this._joint = joint += '-';
}
}
const mySet = new MyCoordinateSet('*');
beforeEach(() => {
mySet.add([0, 0]);
mySet.add([0, 1]);
mySet.add([1, 1]);
});
it('should joint to be *-', () => {
expect(mySet.joint).toBe('*-');
});
it('should has, delete', () => {
mySet.delete([0, 1]);
expect(mySet.has([0, 1])).toBe(false);
});
});

View file

@ -229,3 +229,35 @@ describe('HashMap', () => {
expect(hashMap.getAt(1)).toEqual(['key2', 'value2']);
});
});
describe('HashMap for coordinate object keys', () => {
const hashMap: HashMap<[number, number], number> = new HashMap();
const codObjs: [number, number][] = [];
test('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);
}
});
test('get elements in hash map', () => {
for (let i = 0; i < 1000; i++) {
const codObj = codObjs[i];
if (codObj) {
expect(hashMap.get(codObj)).toBe(i);
}
}
});
test('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);
});
});