You can find all the code in this post in the repo Github.
Array prototype related challenges
Something to notice:
- Use
this
within the function to access the original array. - For some methods, copy the original array first and then modify the copied array.
- When iterating over the array, use
Object.hasOwn()
to check if the index exists. - The parameters order of the callback function is:
(element, index, array)
.
Array.prototype.at()
Use (index + len) % len
to support a negative index.
/**
* @param {number} index
* @return {any | undefiend}
*/
// Time: O(1) | Space: O(1)
Array.prototype.myAt = function (index) {
const len = this.length;
if (index < -len || index >= len) {
return;
}
return this[(index + len) % len];
};
// Usage example
console.log([1, 2, 3, 4].myAt(2)); // => 3
console.log([1, 2, 3, 4].myAt(-1)); // => 4
console.log([1, 2, 3, 4].myAt(5)); // => undefined
Array.prototype.concat()
Copy the original array first and add the rest arrays.
/**
* @template T
* @param {...(T | Array<T>)} itemes
* @return {Array<T>}
*/
// Time: O(n) | Space: O(n)
Array.prototype.myConcat = function (...items) {
const newArray = [...this];
for (const item of items) {
if (Array.isArray(item)) {
newArray.push(...item);
} else {
newArray.push(item);
}
}
return newArray;
};
// Usage example
console.log([1, 2, 3].myConcat([])); // => [1, 2, 3];
console.log([1, 2, 3].myConcat([4, 5, 6, [2]])); // => [1, 2, 3, 4, 5, 6, [2]];
Array.prototype.every()
Use a flag variable.
/**
* @template T
* @param { (value: T, index: number, array: Array<T>) => boolean } callbackFn
* @param {any} [thisArg]
* @return {boolean}
*/
// Time: O(n) | Space: O(1)
Array.prototype.myEvery = function (callbackFn, thisArg) {
const len = this.length;
let flag = true;
for (let i = 0; i < len; i += 1) {
if (Object.hasOwn(this, i) && !callbackFn.call(thisArg, this[i], i, this)) {
flag = false;
break;
}
}
return flag;
};
// Usage example
console.log([1, 2, 3].myEvery((item) => item > 2)); // => false
console.log([1, 2, 3].myEvery((item) => item > 0)); // => true
Array.prototype.filter()
Use the callback function as the conditional filter function.
/**
* @template T, U
* @param { (value: T, index: number, array: Array<T>) => boolean } callbackFn
* @param { any } [thisArg]
* @return {Array<T>}
*/
// Time: O(n) | Space: O(n)
Array.prototype.myFilter = function (callbackFn, thisArg) {
const newArray = [];
for (let i = 0; i < this.length; i += 1) {
if (Object.hasOwn(this, i) && callbackFn.call(thisArg, this[i], i, this)) {
newArray.push(this[i]);
}
}
return newArray;
};
// Usage example
console.log([1, 2, 3, 4].myFilter((value) => value % 2 == 0)); // => [2, 4]
console.log([1, 2, 3, 4].myFilter((value) => value < 3)); // => [1, 2]
Array.prototype.flat()
Recursively flatten the given array based on the depth.
/**
* @param { Array } arr
* @param { number } depth
* @returns { Array }
*/
// Time: O(n) | Space: O(n)
function flatten(arr, depth = 1) {
const newArray = [];
for (let i = 0; i < arr.length; i += 1) {
if (Array.isArray(arr[i]) && depth !== 0) {
newArray.push(...flatten(arr[i], depth - 1));
} else {
newArray.push(arr[i]);
}
}
return newArray;
}
// Usage example
const array = [[1, 2], [1], 1, [[[1]]]];
console.log(flatten(array)); // => [ 1, 2, 1, 1, [ [ 1 ] ] ]
Array.prototype.flatMap()
/**
* @param {functioon} callbackFn
* @param {object | undefined} thisArg
* @return {array}
*/
// Time: O(1) | Space: O(1)
Array.prototype.myFlatMap = function (callbackFn, thisArg) {
return this.reduce((result, element, index, array) => {
const mappedValue = callbackFn.call(thisArg, element, index, array);
return result.concat(mappedValue);
}, []);
};
// Usage example
const arr1 = [1, 2, 1];
const result = arr1.myFlatMap((num) => (num === 2 ? [2, 2] : 1));
console.log(result); // => [1, 2, 2, 1];
Array.prototype.forEach()
Invoking callback function on every item in the array.
/**
* @template T, U
* @param { (value: T, index: number, array: Array<T>) => U } callbackFn
* @param {any} [thisArg]
* @return {Array<U>}
*/
// Time: O(n) | Space: O(1)
Array.prototype.myForEach = function (callbackFn, thisArg) {
if (this == null) {
throw new TypeError("this is null or not defined");
}
if (typeof callbackFn !== "function") {
throw new TypeError(callbackFn + " is not a function");
}
const O = Object(this);
// Zero-fill Right Shift to ensure that the result if always non-negative.
const len = O.length >>> 0;
for (let i = 0; i < len; i += 1) {
if (Object.hasOwn(O, i)) {
callbackFn.call(thisArg, O[i], i, O);
}
}
};
// Usage example
console.log(
[1, 2, 3].myForEach((el) => el * el),
null
); // => [1, 4, 9];
Array.prototype.indexOf()
Iterates over the array to find the index of the first occurrence of the specified element.
/**
* @param {any} searchElement
* @param {number} fromIndex
* @return {number}
*/
// Time: O(n) | Space: O(1)
Array.prototype.myIndexOf = function (searchElement, fromIndex = 0) {
const len = this.length;
if (fromIndex < 0) {
fromIndex = Math.max(0, fromIndex + this.length);
}
for (let i = fromIndex; i < len; i += 1) {
if (this[i] === searchElement) {
return i;
}
}
return -1;
};
// Usage example
console.log([1, 2, 3, 4, 5].myIndexOf(3)); // => 2
console.log([1, 2, 3, 4, 5].myIndexOf(6)); // => -1
console.log([1, 2, 3, 4, 5].myIndexOf(1)); // => 0
console.log(["a", "b", "c"].myIndexOf("b")); // => 1
console.log([NaN].myIndexOf(NaN)); // => -1 (since NaN !== NaN)
Array.prototype.last()
Return the last element in the array.
/**
* @return {null|boolean|number|string|Array|Object}
*/
// Time: O(1) | Space: O(1)
Array.prototype.myLast = function () {
return this.length ? this.at(-1) : -1;
// or
// return this.length ? this[this.length - 1] : -1;
};
// Usage example
console.log([].myLast()); // => -1;
console.log([1].myLast()); // => 1
console.log([1, 2].myLast()); // => 2
Array.prototype.map()
Similar to .forEach()
but returns a new array.
/**
* @template T, U
* @param { (value: T, index: number, array: Array<T>) => U } callbackFn
* @param {any} [thisArg]
* @return {Array<U>}
*/
// Time: O(n) | Space: O(n)
Array.prototype.myMap = function (callbackFn, thisArg) {
const len = this.length;
const newArray = Array.from({ length: len });
for (let i = 0; i < len; i += 1) {
if (Object.hasOwn(this, i)) {
newArray[i] = callbackFn.call(thisArg, this[i], i, this);
}
}
return newArray;
};
// Usage example
console.log([1, 2, 3, 4].myMap((i) => i)); // => [1, 2, 3, 4]
console.log([1, 2, 3, 4].myMap((i) => i * i)); // => [1, 4, 9, 16])
Array.prototype.reduce()
Invoking the callback function on the accumulator.
/**
* @template T, U
* @param { (previousValue: U, currentValue: T, currentIndex: number, array: Array<T>) => U } callbackFn
* @param {U} [initialValue]
* @return {U}
*/
// Time: O(n) | Space: O(1)
Array.prototype.myReduce = function (callbackFn, initialValue) {
const hasInitialValue = initialValue !== undefined;
const len = this.length;
if (!hasInitialValue && !len) {
throw new Error("Reduce of empty array with no initial value");
}
let accumulator = hasInitialValue ? initialValue : this[0];
let startingIndex = hasInitialValue ? 0 : 1;
for (let i = startingIndex; i < len; i += 1) {
if (Object.hasOwn(this, i)) {
accumulator = callbackFn(accumulator, this[i], i, this);
}
}
return accumulator;
};
// Usage example
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.myReduce((acc, num) => acc + num, 0);
console.log(sum); // => 15
const products = numbers.myReduce((acc, num) => acc * num, 1);
Array.prototype.sample()
/**
* @return {any}
*/
// Time: O(1) | Space: O(1)
Array.prototype.mySample = function () {
const randIdx = Math.floor(Math.random() * this.length);
return this[randIdx];
};
// Usage example
const arr = [1, 2, 3, 4, 5, 6, 7];
console.log(arr.mySample()); // => *
Array.prototype.snail()
It's a reverse-problem of Spiral Matrix of LeetCode.
/**
* @param {number} rowsCount
* @param {number} colsCount
* @return {Array<Array<number>>}
*/
// Time: O(n) | Space: O(n^2)
Array.prototype.snail = function (rowsCount, colsCount) {
if (this.length === 0 || rowsCount * colsCount !== this.length) {
return [];
}
const result = Array.from({ length: rowsCount }, () => {
return Array.from({ length: colsCount }, () => 0);
});
let isReversed = false;
for (let i = 0; i < this.length; i += 1) {
const row = !isReversed ? i % rowsCount : rowsCount - 1 - (i % rowsCount);
const col = Math.floor(i / rowsCount);
result[row][col] = this[i];
if (i % rowsCount === rowsCount - 1) {
isReversed = !isReversed;
}
}
return result;
};
// Usage example
const arr = [
19, 10, 3, 7, 9, 8, 5, 2, 1, 17, 16, 14, 12, 18, 6, 13, 11, 20, 4, 15,
];
console.log(arr.snail(5, 4));
/*
[
[19,17,16,15],
[10,1,14,4],
[3,2,12,20],
[7,5,18,11],
[9,8,6,13]
]
*/
Array.prototype.some()
The solution structure is similar to .every()
.
Use a flag variable.
/**
* @template T
* @param { (value: T, index: number, array: Array<T>) => boolean } callbackFn
* @param {any} [thisArg]
* @return {boolean}
*/
// Time: O(n) | Space: O(1)
Array.prototype.mySome = function (callbackFn, thisArg) {
const len = this.length;
let flag = false;
for (let i = 0; i < len; i += 1) {
if (Object.hasOwn(this, i) && callbackFn.call(thisArg, this[i], i, this)) {
flag = true;
break;
}
}
return flag;
};
// Usage example
console.log([1, 2, 3].mySome((item) => item > 2)); // => true
console.log([1, 2, 3].mySome((item) => item < 0)); // => false
Array.prototype.square()
The solution structure is similar to .map()
.
/**
* @return {Array<number>}
*/
// Time: O(n) | Space: O(n)
Array.prototype.mySquare = function () {
const len = this.length;
const newArray = Array.from({ length: len });
for (let i = 0; i < len; i += 1) {
newArray[i] = this[i] * this[i];
}
return newArray;
};
// Usage example
console.log([1, 2, 3].mySquare()); // => [1, 4, 9];
console.log([].mySquare()); // => [];
Reference
- GreatFrontEnd
- Array.prototype.at() - MDN
- Array.prototype.concat() - MDN
- Array.prototype.every() - MDN
- Array.prototype.filter() - MDN
- Array.prototype.flat() - MDN
- Array.prototype.flatMap() - MDN
- Array.prototype.forEach() - MDN
- Array.prototype.indexOf() - MDN
- Array.prototype.map() - MDN
- Array.prototype.reduce() - MDN
- Array.prototype.some() - MDN
- 2635. Apply Transform Over Each Element in Array - LeetCode
- 2634. Filter Elements from Array - LeetCode
- 2626. Array Reduce Transformation - LeetCode
- 2619. Array Prototype Last - LeetCode
- 2625. Flatten Deeply Nested Array - LeetCode
- 3. implement Array.prototype.flat() - BFE.dev
- 151. implement Array.prototype.map() - BFE.dev
- 146. implement Array.prototype.reduce() - BFE.dev
Top comments (0)