Add more methods to the array helper#41
Conversation
|
@vinayak25 ?? |
|
Hi @AhmedHdeawy I will review it tomorrow and merge. Been super busy in some windows related bugs Thanks! |
| static last<T = any>( | ||
| arr: T[], | ||
| predicate?: ((item: T, index: number, array: T[]) => boolean) | null | ||
| ): T | undefined { | ||
| if (!arr || arr.length === 0) { | ||
| return undefined; | ||
| } | ||
|
|
||
| if (!predicate) { | ||
| return arr[arr.length - 1]; | ||
| } | ||
|
|
||
| for (let i = arr.length - 1; i >= 0; i--) { | ||
| if (predicate(arr[i], i, arr)) { | ||
| return arr[i]; | ||
| } | ||
| } | ||
|
|
||
| return undefined; | ||
| } |
There was a problem hiding this comment.
| static last<T = any>( | |
| arr: T[], | |
| predicate?: ((item: T, index: number, array: T[]) => boolean) | null | |
| ): T | undefined { | |
| if (!arr || arr.length === 0) { | |
| return undefined; | |
| } | |
| if (!predicate) { | |
| return arr[arr.length - 1]; | |
| } | |
| for (let i = arr.length - 1; i >= 0; i--) { | |
| if (predicate(arr[i], i, arr)) { | |
| return arr[i]; | |
| } | |
| } | |
| return undefined; | |
| } | |
| static last<T>(arr: T[], predicate?: (item: T, index: number, array: T[]) => boolean): T | undefined { | |
| if (!arr || arr.length === 0) { | |
| return undefined; | |
| } | |
| if (!predicate) { | |
| return arr[arr.length - 1]; | |
| } | |
| for (let i = arr.length - 1; i >= 0; i--) { | |
| if (predicate(arr[i], i, arr)) { | |
| return arr[i]; | |
| } | |
| } | |
| return undefined; | |
| } |
| static exists<T = any>(arr: T[], key: string | number): boolean { | ||
| if (typeof key === 'number' && key >= 0 && key < arr.length) { | ||
| return true; | ||
| } | ||
|
|
||
| if (typeof key === 'string') { | ||
| const splitKeys = key.split('.'); | ||
| if (!splitKeys.length) return false; | ||
|
|
||
| if (Arr.isArray(arr[splitKeys[0]])) { | ||
| return Arr.exists(arr[splitKeys[0]], splitKeys.slice(1).join('.')); | ||
| } | ||
|
|
||
| if (Obj.isObj(arr[splitKeys[0]])) { | ||
| return Obj.get(arr[splitKeys[0]], splitKeys.slice(1).join('.')) !== undefined; | ||
| } | ||
| } | ||
|
|
||
| return false; | ||
| } |
There was a problem hiding this comment.
| static exists<T = any>(arr: T[], key: string | number): boolean { | |
| if (typeof key === 'number' && key >= 0 && key < arr.length) { | |
| return true; | |
| } | |
| if (typeof key === 'string') { | |
| const splitKeys = key.split('.'); | |
| if (!splitKeys.length) return false; | |
| if (Arr.isArray(arr[splitKeys[0]])) { | |
| return Arr.exists(arr[splitKeys[0]], splitKeys.slice(1).join('.')); | |
| } | |
| if (Obj.isObj(arr[splitKeys[0]])) { | |
| return Obj.get(arr[splitKeys[0]], splitKeys.slice(1).join('.')) !== undefined; | |
| } | |
| } | |
| return false; | |
| } | |
| static exists<T>(arr: T[], key: string | number): boolean { | |
| // If the key is a number, just check if it's a valid index. | |
| if (typeof key === 'number') { | |
| return key >= 0 && key < arr.length; | |
| } | |
| // If the key is a string, treat it as a path like "0.someKey.2" | |
| const splitKeys = key.split('.'); | |
| // Early exit if no path given (e.g. empty string) | |
| if (splitKeys.length === 0 || (splitKeys.length === 1 && splitKeys[0] === '')) { | |
| return false; | |
| } | |
| let current: any = arr; | |
| for (let i = 0; i < splitKeys.length; i++) { | |
| let currentKey = splitKeys[i]; | |
| // Check if currentKey should be an array index | |
| const isIndex = !isNaN(parseInt(currentKey)); | |
| if (Array.isArray(current)) { | |
| if (!isIndex) { | |
| // The path expects a number index, but got a string that isn't a number | |
| return false; | |
| } | |
| const idx = parseInt(currentKey, 10); | |
| if (idx < 0 || idx >= current.length) { | |
| return false; | |
| } | |
| current = current[idx]; | |
| } else if (current !== null && typeof current === 'object') { | |
| // For objects, currentKey must be a string property | |
| if (!(currentKey in current)) { | |
| return false; | |
| } | |
| current = current[currentKey]; | |
| } else { | |
| // current is neither an array nor an object; no further traversal possible | |
| return false; | |
| } | |
| } | |
| // If we've navigated the entire path without issues, it exists | |
| return true; | |
| } |
| describe('Array Helper', () => { | ||
| beforeEach(async () => { }); | ||
|
|
||
| it('check key exists', () => { | ||
| const arr = [1, 2, 3, 4, 5]; | ||
| expect(Arr.exists(arr, 2)).toBeTruthy(); | ||
| }); | ||
|
|
||
| it('check key does not exist', () => { | ||
| const arr = [1, 2, 3, 4, 5]; | ||
| expect(Arr.exists(arr, 6)).toBeFalsy(); | ||
| }); | ||
|
|
||
| it('should return last element matching predicate', () => { | ||
| const arr = [1, 2, 3, 4, 5]; | ||
| expect(Arr.last(arr, x => x < 4)).toBe(3); | ||
| expect(Arr.last(arr)).toBe(5); | ||
| }); | ||
|
|
||
| it('should return the last object that matches the predicate', () => { | ||
| const users = [ | ||
| { name: 'Alice', age: 25 }, | ||
| { name: 'Bob', age: 30 }, | ||
| { name: 'Charlie', age: 35 }, | ||
| { name: 'David', age: 30 } | ||
| ]; | ||
| const lastUserUnder35 = Arr.last(users, user => user.age < 35); | ||
| expect(lastUserUnder35).toEqual({ name: 'David', age: 30 }); | ||
| }); | ||
|
|
||
| it('should return undefined for empty array', () => { | ||
| expect(Arr.last([])).toBeUndefined(); | ||
| }); | ||
| }); |
There was a problem hiding this comment.
| describe('Array Helper', () => { | |
| beforeEach(async () => { }); | |
| it('check key exists', () => { | |
| const arr = [1, 2, 3, 4, 5]; | |
| expect(Arr.exists(arr, 2)).toBeTruthy(); | |
| }); | |
| it('check key does not exist', () => { | |
| const arr = [1, 2, 3, 4, 5]; | |
| expect(Arr.exists(arr, 6)).toBeFalsy(); | |
| }); | |
| it('should return last element matching predicate', () => { | |
| const arr = [1, 2, 3, 4, 5]; | |
| expect(Arr.last(arr, x => x < 4)).toBe(3); | |
| expect(Arr.last(arr)).toBe(5); | |
| }); | |
| it('should return the last object that matches the predicate', () => { | |
| const users = [ | |
| { name: 'Alice', age: 25 }, | |
| { name: 'Bob', age: 30 }, | |
| { name: 'Charlie', age: 35 }, | |
| { name: 'David', age: 30 } | |
| ]; | |
| const lastUserUnder35 = Arr.last(users, user => user.age < 35); | |
| expect(lastUserUnder35).toEqual({ name: 'David', age: 30 }); | |
| }); | |
| it('should return undefined for empty array', () => { | |
| expect(Arr.last([])).toBeUndefined(); | |
| }); | |
| }); | |
| describe('Arr Utility Class', () => { | |
| describe('Arr.exists', () => { | |
| const sampleArray = [1, 2, { name: 'Alice', friends: ['Bob', 'Carol'] }]; | |
| const arr = [1, 2, 3, 4, 5]; | |
| it('check key exists', () => { | |
| expect(Arr.exists(arr, 2)).toBeTruthy(); | |
| }); | |
| it('check key does not exist', () => { | |
| expect(Arr.exists(arr, 6)).toBeFalsy(); | |
| }); | |
| it('should return true for a valid index (0)', () => { | |
| expect(Arr.exists(sampleArray, 0)).toBe(true); | |
| }); | |
| it('should return true for a nested property ("2.name")', () => { | |
| expect(Arr.exists(sampleArray, '2.name')).toBe(true); | |
| }); | |
| it('should return true for a deeper nested array property ("2.friends.1")', () => { | |
| expect(Arr.exists(sampleArray, '2.friends.1')).toBe(true); | |
| }); | |
| it('should return false for a non-existent property ("2.age")', () => { | |
| expect(Arr.exists(sampleArray, '2.age')).toBe(false); | |
| }); | |
| }); | |
| describe('Arr.last', () => { | |
| it('should return last element matching predicate', () => { | |
| const arr = [1, 2, 3, 4, 5]; | |
| expect(Arr.last(arr, x => x < 4)).toBe(3); | |
| expect(Arr.last(arr)).toBe(5); | |
| }); | |
| it('should return the last object that matches the predicate', () => { | |
| const users = [ | |
| { name: 'Alice', age: 25 }, | |
| { name: 'Bob', age: 30 }, | |
| { name: 'Charlie', age: 35 }, | |
| { name: 'David', age: 30 }, | |
| ]; | |
| const lastUserUnder35 = Arr.last(users, user => user.age < 35); | |
| expect(lastUserUnder35).toEqual({ name: 'David', age: 30 }); | |
| }); | |
| it('should return undefined for empty array', () => { | |
| expect(Arr.last([])).toBeUndefined(); | |
| }); | |
| }); | |
| }); |
vikashviraj
left a comment
There was a problem hiding this comment.
Many thanks, @AhmedHdeawy, for your contribution. I just added a few suggestions. If they look good, feel free to accept them.
FYI: @vinayak25
Hi @vikashviraj thanks for your contribution. Could you please clarify the reasoning behind the changes, especially the additions to the |
|
@vinayak25 Have you reviewed it? |
…Hdeawy/intent-framework into impr/add-more-array-helper-methods
|
Hi @vinayak25 I've updated the code and fixed all linting issues. |
Feat: Added
existsandlastmethods to the array helper.I wrote test cases as well for both.