// https://blog.logrocket.com/understand-array-methods-by-implementing-them/
// UTIL FUNCTION
function logOperation(operationName, array, callback) {
const input = [...array];
const result = callback(array);
console.log({
operation: operationName,
arrayBefore: input,
arrayAfter: array,
//mutates: mutatesArray(input, array), // shallow check
result,
});
}
/*
_ __
_|_ _ __|_ _ _ |_
| (_) | |__(_|(_ | |
[1, 2, 3, 4, 5].forEach(value => console.log(value));
*/
function forEach(array, callback) {
const { length } = array;
for (let index = 0; index < length; index += 1) {
const value = array[index];
callback(value, index, array);
}
}
logOperation('forEach', [1, 2, 3, 4, 5], array => forEach(array, value => console.log(value)));
/*
_ _
|V||_||_)
o | || ||
[1, 2, 3].map(number => number * 5);
*/
function map(array, callback) {
const result = [];
const { length } = array;
for (let index = 0; index < length; index += 1) {
const value = array[index];
result[index] = callback(value, index, array);
}
return result;
}
logOperation('map', [1, 2, 3, 4, 5], array => map(array, value => value + 5));
/*
_____ ___ __ _
|_ | | | |_ |_)
o | _|_|__ | |__| \
[1, 2, 3, 4, 5].filter(number => number >= 3);
*/
function filter(array, callback) {
const result = [];
const { length } = array;
for (let index = 0; index < length; index += 1) {
const value = array[index];
if (callback(value, index, array)) {
push(result, value); // 🚩 an issue, push method doesn't exist
}
}
return result;
}
logOperation('filter', [1, 2, 3, 4, 5], array => filter(array, value => value >= 2));
/*
_ __ _ __ __
|_)|_ | \| |/ |_
o | \|__|_/|_|\__|__
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].reduce((sum, number) => {
return sum + number;
}, 0);
*/
function reduce(array, callback, initValue) {
const { length } = array;
let acc = initValue;
let startAtIndex = 0;
if (initValue === undefined) {
acc = array[0];
startAtIndex = 1;
}
for (let index = startAtIndex; index < length; index += 1) {
const value = array[index];
acc = callback(acc, value, index, array);
}
return acc;
}
logOperation('reduce', [1, 2, 3, 4, 5], array => reduce(array, (sum, number) => sum + number, 0));
/*
_ ___ _ __\ /
_|_ o __ _| | |\|| \|_ X
o | | | |(_|_|_| ||_/|__/ \
[1, 2, 3, 4, 5, 6, 7].findIndex(value => value === 5); // 4
*/
function findIndex(array, callback) {
const { length } = array;
for (let index = 0; index < length; index += 1) {
const value = array[index];
if (callback(value, index, array)) {
return index;
}
}
return -1;
}
logOperation('findIndex', [1, 2, 3, 4, 5], array => findIndex(array, number => number === 3));
/*
_
_|_ o __ _|
o | | | |(_|
[1, 2, 3, 4, 5, 6, 7].find(value => value === 5); // 4
*/
function find(array, callback) {
const index = findIndex(array, callback);
if (index === -1) {
return undefined;
}
return array[index];
}
logOperation('find', [1, 2, 3, 4, 5], array => find(array, number => number === 3));
/*
_ _
o __ _| _ / \_|_
o | | |(_|(/_>< \_/ |
[3, 2, 3].indexOf(3); // -> 0
*/
function indexOf(array, searchedValue) {
return findIndex(array, value => value === searchedValue);
}
logOperation('indexOf', [1, 2, 3, 4, 5], array => indexOf(array, 3));
/*
___ _ _
| _ _ _|_ | __ _| _ / \_|_
o | (_|_> |__|_| |(_|(/_>< \_/ |
[3, 2, 3].lastIndexOf(3); // -> 2
*/
function lastIndexOf(array, searchedValue) {
for (let index = array.length - 1; index > -1; index -= 1) {
const value = array[index];
if (value === searchedValue) {
return index;
}
}
return -1;
}
logOperation('lastIndexOf', [1, 2, 3, 4, 5, 3], array => lastIndexOf(array, 3));
/*
_ _ __ \/
o (/_\_/(/_ | /
[1, 2, 3].every(value => Number.isInteger(value)); // -> true
*/
function every(array, callback) {
const { length } = array;
for (let index = 0; index < length; index += 1) {
const value = array[index];
if (!callback(value, index, array)) {
return false;
}
}
return true;
}
logOperation('every', [1, 2, 3, 4, 5], array => every(array, number => Number.isInteger(number)));
/*
_ _ __ _
o _> (_)|||(/_
[1, 2, 3, 4, 5].some(number => number === 5); // -> true
*/
function some(array, callback) {
const { length } = array;
for (let index = 0; index < length; index += 1) {
const value = array[index];
if (callback(value, index, array)) {
return true;
}
}
return false;
}
logOperation('some', [1, 2, 3, 4, 5], array => some(array, number => number === 5));
/*
o __ _ | _| _ _
o | | |(_ | |_|(_|(/__>
[1, 2, 3].includes(3); // -> true
*/
function includes(array, searchedValue) {
return some(array, value => value === searchedValue);
}
logOperation('includes', [1, 2, 3, 4, 5], array => includes(array, 5));
/*
_
_|_ | _ _|_
o | | (_| |_
[1, 2, 3, [4, 5]].flat(1) // -> [1, 2, 3, 4, 5]
*/
function flat(array, depth = 0) {
if (depth < 1 || !Array.isArray(array)) {
return array;
}
return reduce( // 🚩
array,
(result, current) => {
return concat(result, flat(current, depth - 1));
},
[],
);
}
logOperation('flat', [1, 2, 3, [4, 5, [6]]], array => flat(array, 2));
/*
_ _
_|_ | _ _|_|V| _ |_)
o | | (_| |_| |(_||
[1, 2, 3].flatMap(value => [value, value, value]); // [1, 1, 1, 2, 2, 2, 3, 3, 3]
*/
function flatMap(array, callback) {
return flat(map(array, callback), 1);
}
logOperation('flatMap', [1, 2, 3], array => flatMap(array, number => [number, number]));
/*
_ _ __ _ _ _|_
o (_ (_)| |(_ (_| |_
[1, 2, 3].concat([4, 5], 6, [7, 8]) // -> [1, 2, 3, 4, 5, 6, 7, 8]
*/
function concat(array, ...values) {
const result = [...array];
const { length } = values;
for (let index = 0; index < length; index += 1) {
const value = values[index];
if (Array.isArray(value)) {
push(result, ...value);
} else {
push(result, value);
}
}
return result;
}
logOperation('concat', [1, 2, 3, 4, 5], array => concat(array, 1, 2, [3, 4]));
/*
o
| _ o __
o _| (_) | | |
['Brian', 'Matt', 'Kate'].join(', ') // -> Brian, Matt, Kate
*/
function join(array, joinWith) {
return reduce(
array,
(result, current, index) => {
if (index === 0) {
return current;
}
return `${result}${joinWith}${current}`;
},
'',
);
}
logOperation('join', [1, 2, 3, 4, 5], array => join(array, ', '));
/*
__ _ _ __ _ _
o | (/_\_/(/_ | _> (/_
[1, 2, 3].reverse(); // -> [3, 2, 1]
*/
function reverse(array) {
const result = [];
const lastIndex = array.length - 1;
for (let index = lastIndex; index > -1; index -= 1) {
const value = array[index];
result[lastIndex - index] = value;
}
return result;
}
logOperation('reverse', [1, 2, 3, 4, 5], array => reverse(array));
/*
_
_ |_ o _|__|_
o _> | | | | |_
[1, 2, 3].shift(); // -> 1
*/
function shift(array) {
const { length } = array;
const firstValue = array[0];
for (let index = 1; index < length; index += 1) {
const value = array[index];
array[index - 1] = value;
}
array.length = length - 1;
return firstValue;
}
logOperation('shift', [1, 2, 3, 4, 5], array => shift(array));
/*
_
__ _ |_ o _|__|_
o |_|| |_> | | | | |_
[2, 3, 4].unshift(1); // -> [1, 2, 3, 4]
*/
function unshift(array, ...values) {
const mergedArrays = concat(values, ...array);
const { length: mergedArraysLength } = mergedArrays;
for (let index = 0; index < mergedArraysLength; index += 1) {
const value = mergedArrays[index];
array[index] = value;
}
return array.length;
}
logOperation('unshift', [1, 2, 3, 4, 5], array => unshift(array, 0));
/*
_ | o _ _
o _> | | (_ (/_
[1, 2, 3, 4, 5, 6, 7].slice(3, 6); // -> [4, 5, 6]
*/
function slice(array, startIndex = 0, endIndex = array.length) {
const result = [];
for (let index = startIndex; index < endIndex; index += 1) {
const value = array[index];
if (index < array.length) {
push(result, value);
}
}
return result;
}
logOperation('slice', [1, 2, 3, 4, 5], array => slice(array, 1, 3));
/*
_
_ |_) | o _ _
o _> | | | (_ (/_
const arr = [1, 2, 3, 4, 5];
arr.splice(0, 2, 3, 4, 5);
arr // -> [3, 4, 5, 3, 4, 5]
*/
function splice<T>(array: T[], insertAtIndex: number, removeNumberOfElements: number, ...values: T[]) {
const firstPart = slice(array, 0, insertAtIndex);
const secondPart = slice(array, insertAtIndex + removeNumberOfElements);
const removedElements = slice(array, insertAtIndex, insertAtIndex + removeNumberOfElements);
const joinedParts = firstPart.concat(values, secondPart);
const { length: joinedPartsLength } = joinedParts;
for (let index = 0; index < joinedPartsLength; index += 1) {
array[index] = joinedParts[index];
}
array.length = joinedPartsLength;
return removedElements;
}
logOperation('splice', [1, 2, 3, 4, 5], array => splice(array, 1, 3));
/*
_ _
|_) _ |_)
o | (_)|
[1, 2, 3].pop(); // -> 3
*/
function pop(array) {
const value = array[array.length - 1];
array.length = array.length - 1;
return value;
}
logOperation('pop', [1, 2, 3, 4, 5], array => pop(array));
/*
_
|_) _ |_
o | |_|_> | |
[1, 2, 3, 4].push(5); // -> [1, 2, 3, 4, 5]
*/
export function push(array, ...values) {
const { length: arrayLength } = array;
const { length: valuesLength } = values;
for (let index = 0; index < valuesLength; index += 1) {
array[arrayLength + index] = values[index];
}
return array.length;
}
logOperation('push', [1, 2, 3, 4, 5], array => push(array, 6, 7));
/*
_
_|_ o | |
o | | | |
[...Array(5)].fill(null) // -> [null, null, null, null, null]
*/
function fill(array, value, startIndex = 0, endIndex = array.length) {
for (let index = startIndex; index < endIndex; index += 1) {
array[index] = value;
}
return array;
}
logOperation('fill', [...new Array(5)], array => fill(array, 0));
/*
_ | _ _
o \_/(_| | |_|(/__>
const valuesGenerator = values([1, 2, 3, 4, 5]);
valuesGenerator.next(); // { value: 1, done: false }
*/
function values(array) {
const { length } = array;
function* createGenerator() {
for (let index = 0; index < length; index += 1) {
const value = array[index];
yield value;
}
}
return createGenerator();
}
/*
| _ \/ _
o |<(/_ / _>
const keysGenerator = keys([1, 2, 3, 4, 5]);
keysGenerator.next(); // { value: 0, done: false }
*/
function keys(array) {
function* createGenerator() {
const { length } = array;
for (let index = 0; index < length; index += 1) {
yield index;
}
}
return createGenerator();
}
/*
_ __ _|_ __ o _ _
o (/_| | |_ | | (/__>
const entriesGenerator = entries([1, 2, 3, 4, 5]);
entriesGenerator.next(); // { value: [0, 1], done: false }
*/
function entries(array) {
const { length } = array;
function* createGenerator() {
for (let index = 0; index < length; index += 1) {
const value = array[index];
yield [index, value];
}
}
return createGenerator();
}