From ff8f90719213177470a27c2e22eb117e7602301f Mon Sep 17 00:00:00 2001 From: Revone Date: Sat, 30 Dec 2023 18:44:24 +0800 Subject: [PATCH] feat: In the IterableEntryBase and IterableElementBase classes, add find, get, and has methods so that all inheriting data structures can have access to these methods. Also, override these methods in the necessary data structures as needed. --- src/data-structures/base/iterable-base.ts | 183 ++++++++++++++++-- .../binary-tree/binary-tree.ts | 4 +- src/data-structures/hash/hash-map.ts | 4 +- .../linked-list/doubly-linked-list.ts | 26 --- .../linked-list/singly-linked-list.ts | 26 --- src/data-structures/queue/deque.ts | 26 --- .../linked-list/doubly-linked-list.test.ts | 2 + .../linked-list/singly-linked-list.test.ts | 1 + 8 files changed, 171 insertions(+), 101 deletions(-) diff --git a/src/data-structures/base/iterable-base.ts b/src/data-structures/base/iterable-base.ts index b9333e0..968438a 100644 --- a/src/data-structures/base/iterable-base.ts +++ b/src/data-structures/base/iterable-base.ts @@ -154,6 +154,105 @@ export abstract class IterableEntryBase { * Time Complexity: O(n) * Space Complexity: O(1) */ + + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + * + * The `find` function iterates over the entries of a collection and returns the first value for + * which the callback function returns true. + * @param callbackfn - The callback function that will be called for each entry in the collection. It + * takes three arguments: the value of the entry, the key of the entry, and the index of the entry in + * the collection. It should return a boolean value indicating whether the current entry matches the + * desired condition. + * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value + * to be used as `this` when executing the `callbackfn` function. If `thisArg` is provided, it will + * be passed as the `this` value to the `callbackfn` function. If `thisArg + * @returns The method `find` returns the value of the first element in the iterable that satisfies + * the provided callback function. If no element satisfies the callback function, `undefined` is + * returned. + */ + find(callbackfn: EntryCallback, thisArg?: any): [K, V] | undefined { + let index = 0; + for (const item of this) { + const [key, value] = item; + if (callbackfn.call(thisArg, value, key, index++, this)) return item; + } + return; + } + + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + */ + + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + * + * The function checks if a given key exists in a collection. + * @param {K} key - The parameter "key" is of type K, which means it can be any type. It represents + * the key that we want to check for existence in the data structure. + * @returns a boolean value. It returns true if the key is found in the collection, and false + * otherwise. + */ + has(key: K): boolean { + for (const item of this) { + const [itemKey] = item; + if (itemKey === key) return true; + } + return false; + } + + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + */ + + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + * + * The function checks if a given value exists in a collection. + * @param {V} value - The parameter "value" is the value that we want to check if it exists in the + * collection. + * @returns a boolean value, either true or false. + */ + hasValue(value: V): boolean { + for (const [, elementValue] of this) { + if (elementValue === value) return true; + } + return false; + } + + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + */ + + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + * + * The `get` function retrieves the value associated with a given key from a collection. + * @param {K} key - K (the type of the key) - This parameter represents the key that is being + * searched for in the collection. + * @returns The `get` method returns the value associated with the specified key if it exists in the + * collection, otherwise it returns `undefined`. + */ + get(key: K): V | undefined { + for (const item of this) { + const [itemKey, value] = item; + if (itemKey === key) return value; + } + return; + } + + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + */ + /** * Time Complexity: O(n) * Space Complexity: O(1) @@ -180,13 +279,6 @@ export abstract class IterableEntryBase { return accumulator; } - hasValue(value: V): boolean { - for (const [, elementValue] of this) { - if (elementValue === value) return true; - } - return false; - } - /** * Time Complexity: O(n) * Space Complexity: O(n) @@ -198,7 +290,7 @@ export abstract class IterableEntryBase { protected abstract _getIterator(...args: any[]): IterableIterator<[K, V]>; } -export abstract class IterableElementBase { +export abstract class IterableElementBase { /** * Time Complexity: O(n) * Space Complexity: O(1) @@ -212,7 +304,7 @@ export abstract class IterableElementBase { * allows the function to accept any number of arguments as an array. In this case, the `args` * parameter is used to pass any number of arguments to the `_getIterator` method. */ - * [Symbol.iterator](...args: any[]): IterableIterator { + * [Symbol.iterator](...args: any[]): IterableIterator { yield* this._getIterator(...args); } @@ -226,7 +318,7 @@ export abstract class IterableElementBase { * * The function returns an iterator that yields all the values in the object. */ - * values(): IterableIterator { + * values(): IterableIterator { for (const item of this) { yield item; } @@ -250,10 +342,10 @@ export abstract class IterableElementBase { * @returns The `every` method is returning a boolean value. It returns `true` if every element in * the array satisfies the provided predicate function, and `false` otherwise. */ - every(predicate: ElementCallback, thisArg?: any): boolean { + every(predicate: ElementCallback, thisArg?: any): boolean { let index = 0; for (const item of this) { - if (!predicate.call(thisArg, item as V, index++, this)) { + if (!predicate.call(thisArg, item, index++, this)) { return false; } } @@ -278,10 +370,10 @@ export abstract class IterableElementBase { * @returns a boolean value. It returns true if the predicate function returns true for any element * in the collection, and false otherwise. */ - some(predicate: ElementCallback, thisArg?: any): boolean { + some(predicate: ElementCallback, thisArg?: any): boolean { let index = 0; for (const item of this) { - if (predicate.call(thisArg, item as V, index++, this)) { + if (predicate.call(thisArg, item, index++, this)) { return true; } } @@ -292,6 +384,7 @@ export abstract class IterableElementBase { * Time Complexity: O(n) * Space Complexity: O(1) */ + /** * Time Complexity: O(n) * Space Complexity: O(1) @@ -305,13 +398,65 @@ export abstract class IterableElementBase { * to be used as `this` when executing the `callbackfn` function. If `thisArg` is provided, it will * be passed as the `this` value to the `callbackfn` function. If `thisArg */ - forEach(callbackfn: ElementCallback, thisArg?: any): void { + forEach(callbackfn: ElementCallback, thisArg?: any): void { let index = 0; for (const item of this) { - callbackfn.call(thisArg, item as V, index++, this); + callbackfn.call(thisArg, item, index++, this); } } + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + */ + + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + * + * The `find` function iterates over the elements of an array-like object and returns the first + * element that satisfies the provided callback function. + * @param callbackfn - The callbackfn parameter is a function that will be called for each element in + * the array. It takes three arguments: the current element being processed, the index of the current + * element, and the array itself. The function should return a boolean value indicating whether the + * current element matches the desired condition. + * @param {any} [thisArg] - The `thisArg` parameter is an optional argument that specifies the value + * to be used as `this` when executing the `callbackfn` function. If `thisArg` is provided, it will + * be passed as the `this` value to the `callbackfn` function. If `thisArg + * @returns The `find` method returns the first element in the array that satisfies the provided + * callback function. If no element satisfies the callback function, `undefined` is returned. + */ + find(callbackfn: ElementCallback, thisArg?: any): E | undefined { + let index = 0; + for (const item of this) { + if (callbackfn.call(thisArg, item, index++, this)) return item; + } + + return; + } + + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + */ + + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + * + * The function checks if a given element exists in a collection. + * @param {E} element - The parameter "element" is of type E, which means it can be any type. It + * represents the element that we want to check for existence in the collection. + * @returns a boolean value. It returns true if the element is found in the collection, and false + * otherwise. + */ + has(element: E): boolean { + for (const ele of this) { + if (ele === element) return true; + } + return false; + } + /** * Time Complexity: O(n) * Space Complexity: O(1) @@ -329,11 +474,11 @@ export abstract class IterableElementBase { * @returns The `reduce` method is returning the final value of the accumulator after iterating over * all the elements in the array and applying the callback function to each element. */ - reduce(callbackfn: ReduceElementCallback, initialValue: U): U { + reduce(callbackfn: ReduceElementCallback, initialValue: U): U { let accumulator = initialValue; let index = 0; for (const item of this) { - accumulator = callbackfn(accumulator, item as V, index++, this); + accumulator = callbackfn(accumulator, item as E, index++, this); } return accumulator; } @@ -346,5 +491,5 @@ export abstract class IterableElementBase { console.log([...this]); } - protected abstract _getIterator(...args: any[]): IterableIterator; + protected abstract _getIterator(...args: any[]): IterableIterator; } diff --git a/src/data-structures/binary-tree/binary-tree.ts b/src/data-structures/binary-tree/binary-tree.ts index 32c309b..b3494f4 100644 --- a/src/data-structures/binary-tree/binary-tree.ts +++ b/src/data-structures/binary-tree/binary-tree.ts @@ -810,7 +810,7 @@ export class BinaryTree< * be performed in a pre-order, in-order, or post-order manner. * @returns a boolean value. */ - has>( + override has>( identifier: ReturnType | null | undefined, callback: C = this._defaultOneParamCallback as C, beginRoot: KeyOrNodeOrEntry = this.root, @@ -968,7 +968,7 @@ export class BinaryTree< * @returns The value of the node with the given identifier is being returned. If the node is not * found, `undefined` is returned. */ - get>( + override get>( identifier: ReturnType | null | undefined, callback: C = this._defaultOneParamCallback as C, beginRoot: KeyOrNodeOrEntry = this.root, diff --git a/src/data-structures/hash/hash-map.ts b/src/data-structures/hash/hash-map.ts index dca1144..9d7a56e 100644 --- a/src/data-structures/hash/hash-map.ts +++ b/src/data-structures/hash/hash-map.ts @@ -147,7 +147,7 @@ export class HashMap extends IterableEntryBase extends IterableEntryBase { * property of the key. If the key is a string key, the value is retrieved from the `_noObjMap` object * using the key itself. If the key is not found, `undefined` is */ - get(key: K): V | undefined { + override get(key: K): V | undefined { if (isWeakKey(key)) { const hash = this._objHashFn(key); const node = this._objMap.get(hash); diff --git a/src/data-structures/linked-list/doubly-linked-list.ts b/src/data-structures/linked-list/doubly-linked-list.ts index 5413188..8298e0f 100644 --- a/src/data-structures/linked-list/doubly-linked-list.ts +++ b/src/data-structures/linked-list/doubly-linked-list.ts @@ -520,32 +520,6 @@ export class DoublyLinkedList extends IterableElementBase { this._size = 0; } - /** - * Time Complexity: O(n), where n is the number of elements in the linked list. - * Space Complexity: O(1) - */ - - /** - * Time Complexity: O(n), where n is the number of elements in the linked list. - * Space Complexity: O(1) - * - * The `find` function iterates through a linked list and returns the first element that satisfies a given condition. - * @param callback - A function that takes a value of type E as its parameter and returns a boolean value. This - * function is used to determine whether a particular value in the linked list satisfies a certain condition. - * @returns The method `find` returns the first element in the linked list that satisfies the condition specified by - * the callback function. If no element satisfies the condition, it returns `undefined`. - */ - find(callback: (value: E) => boolean): E | undefined { - let current = this.head; - while (current) { - if (callback(current.value)) { - return current.value; - } - current = current.next; - } - return undefined; - } - /** * Time Complexity: O(n), where n is the number of elements in the linked list. * Space Complexity: O(1) diff --git a/src/data-structures/linked-list/singly-linked-list.ts b/src/data-structures/linked-list/singly-linked-list.ts index f4773dc..8c064b3 100644 --- a/src/data-structures/linked-list/singly-linked-list.ts +++ b/src/data-structures/linked-list/singly-linked-list.ts @@ -484,32 +484,6 @@ export class SinglyLinkedList extends IterableElementBase { return this; } - /** - * Time Complexity: O(n) - Linear time, where n is the length of the list, as it needs to reverse the pointers of each node. - * Space Complexity: O(1) - Constant space. - */ - - /** - * Time Complexity: O(n) - Linear time, where n is the length of the list, as it needs to reverse the pointers of each node. - * Space Complexity: O(1) - Constant space. - * - * The `find` function iterates through a linked list and returns the first element that satisfies a given condition. - * @param callback - A function that takes a value of type E as its parameter and returns a boolean value. This - * function is used to determine whether a particular value in the linked list satisfies a certain condition. - * @returns The method `find` returns the first element in the linked list that satisfies the condition specified by - * the callback function. If no element satisfies the condition, it returns `undefined`. - */ - find(callback: (value: E) => boolean): E | undefined { - let current = this.head; - while (current) { - if (callback(current.value)) { - return current.value; - } - current = current.next; - } - return undefined; - } - /** * Time Complexity: O(n) - Linear time, where n is the length of the list, as it needs to reverse the pointers of each node. * Space Complexity: O(1) - Constant space. diff --git a/src/data-structures/queue/deque.ts b/src/data-structures/queue/deque.ts index db702e1..ac6c2c5 100644 --- a/src/data-structures/queue/deque.ts +++ b/src/data-structures/queue/deque.ts @@ -549,32 +549,6 @@ export class Deque extends IterableElementBase { this._buckets = newBuckets; } - /** - * Time Complexity: O(n) - * Space Complexity: O(1) - */ - - /** - * Time Complexity: O(n) - * Space Complexity: O(1) - * - * The `find` function iterates over the elements in a deque and returns the first element for which - * the callback function returns true, or undefined if no such element is found. - * @param callback - A function that takes three parameters: element, index, and deque. It should - * return a boolean value indicating whether the element satisfies a certain condition. - * @returns The method `find` returns the first element in the deque that satisfies the condition - * specified by the callback function. If no element satisfies the condition, it returns `undefined`. - */ - find(callback: (element: E, index: number, deque: Deque) => boolean): E | undefined { - for (let i = 0; i < this.size; ++i) { - const element = this.getAt(i); - if (callback(element, i, this)) { - return element; - } - } - return; - } - /** * Time Complexity: O(n) * Space Complexity: O(1) diff --git a/test/unit/data-structures/linked-list/doubly-linked-list.test.ts b/test/unit/data-structures/linked-list/doubly-linked-list.test.ts index f5036e4..49a0444 100644 --- a/test/unit/data-structures/linked-list/doubly-linked-list.test.ts +++ b/test/unit/data-structures/linked-list/doubly-linked-list.test.ts @@ -39,6 +39,8 @@ describe('DoublyLinkedList Operation Test', () => { it('should find undefined', () => { expect(list.find(value => value === 6)).toBe(undefined); + expect(list.find(value => value === 4)).toBe(4); + expect(list.find(value => value === 3)).toBe(3); }); it('should indexOf -1', () => { diff --git a/test/unit/data-structures/linked-list/singly-linked-list.test.ts b/test/unit/data-structures/linked-list/singly-linked-list.test.ts index b9debbb..d2dd260 100644 --- a/test/unit/data-structures/linked-list/singly-linked-list.test.ts +++ b/test/unit/data-structures/linked-list/singly-linked-list.test.ts @@ -327,6 +327,7 @@ describe('SinglyLinkedList Operation Test', () => { list.push(3); const result = list.find(data => data % 2 === 0); expect(result).toBe(2); + expect(list.find(value => value === 3)).toBe(3); }); it('should return undefined if element is not found', () => {