Array Methods and Utilities
Array Methods and Utilities
Section titled “Array Methods and Utilities”Arrays are one of the most fundamental and versatile data structures in JavaScript. This comprehensive guide covers all array methods, advanced manipulation techniques, and practical patterns for working with arrays effectively.
Array Creation Methods
Section titled “Array Creation Methods”Static Creation Methods
Section titled “Static Creation Methods”// Array.of() - Create array from argumentsconst numbers = Array.of(1, 2, 3, 4, 5); // [1, 2, 3, 4, 5]const singleItem = Array.of(7); // [7] (not array with 7 empty slots)const mixed = Array.of('a', 1, true, null); // ['a', 1, true, null]
// Array.from() - Create array from iterable or array-likeconst fromString = Array.from('hello'); // ['h', 'e', 'l', 'l', 'o']const fromSet = Array.from(new Set([1, 2, 3])); // [1, 2, 3]const range = Array.from({ length: 5 }, (_, i) => i + 1); // [1, 2, 3, 4, 5]
// Array.from() with mapping functionconst doubled = Array.from([1, 2, 3], x => x * 2); // [2, 4, 6]const squares = Array.from({ length: 5 }, (_, i) => i ** 2); // [0, 1, 4, 9, 16]
// Convert NodeList to Arrayconst elements = Array.from(document.querySelectorAll('div'));
// Convert arguments object to Arrayfunction toArray() { return Array.from(arguments);}
// Array.fromAsync() - ES2023 proposal for async iterablesasync function* asyncGenerator() { for (let i = 0; i < 3; i++) { yield Promise.resolve(i); }}
// const asyncArray = await Array.fromAsync(asyncGenerator()); // [0, 1, 2]
Literal and Constructor Patterns
Section titled “Literal and Constructor Patterns”// Array literals (preferred)const fruits = ['apple', 'banana', 'cherry'];const numbers = [1, 2, 3, 4, 5];const mixed = [1, 'hello', true, null, { id: 1 }];
// Array constructor patternsconst empty = new Array(); // []const withLength = new Array(5); // [undefined × 5]const withElements = new Array(1, 2, 3); // [1, 2, 3]
// Sparse arraysconst sparse = [1, , , 4]; // [1, undefined × 2, 4]console.log(sparse.length); // 4console.log(sparse[1]); // undefinedconsole.log(1 in sparse); // false
// Multi-dimensional arraysconst matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9]];
// Create 2D array dynamicallyfunction create2DArray(rows, cols, defaultValue = null) { return Array.from({ length: rows }, () => Array.from({ length: cols }, () => defaultValue) );}
const grid = create2DArray(3, 3, 0);// [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
Mutating Methods
Section titled “Mutating Methods”Adding and Removing Elements
Section titled “Adding and Removing Elements”const arr = [1, 2, 3];
// push() - Add to end (returns new length)const newLength = arr.push(4, 5); // arr: [1, 2, 3, 4, 5], returns: 5
// pop() - Remove from end (returns removed element)const removed = arr.pop(); // arr: [1, 2, 3, 4], returns: 5
// unshift() - Add to beginning (returns new length)arr.unshift(0); // arr: [0, 1, 2, 3, 4], returns: 5
// shift() - Remove from beginning (returns removed element)const first = arr.shift(); // arr: [1, 2, 3, 4], returns: 0
// Performance comparison: push/pop vs unshift/shiftconsole.time('push/pop');const arr1 = [];for (let i = 0; i < 100000; i++) { arr1.push(i);}for (let i = 0; i < 100000; i++) { arr1.pop();}console.timeEnd('push/pop'); // Usually faster
console.time('unshift/shift');const arr2 = [];for (let i = 0; i < 100000; i++) { arr2.unshift(i);}for (let i = 0; i < 100000; i++) { arr2.shift();}console.timeEnd('unshift/shift'); // Usually slower
Splice Method - Swiss Army Knife
Section titled “Splice Method - Swiss Army Knife”const arr = ['a', 'b', 'c', 'd', 'e'];
// Remove elementsconst removed1 = arr.splice(1, 2); // arr: ['a', 'd', 'e'], removed: ['b', 'c']
// Insert elementsarr.splice(1, 0, 'x', 'y'); // arr: ['a', 'x', 'y', 'd', 'e']
// Replace elementsarr.splice(1, 2, 'z'); // arr: ['a', 'z', 'd', 'e']
// Insert at specific positionfunction insertAt(array, index, ...elements) { array.splice(index, 0, ...elements); return array;}
// Remove all occurrences of a valuefunction removeAll(array, value) { for (let i = array.length - 1; i >= 0; i--) { if (array[i] === value) { array.splice(i, 1); } } return array;}
// Move element from one position to anotherfunction moveElement(array, fromIndex, toIndex) { const element = array.splice(fromIndex, 1)[0]; array.splice(toIndex, 0, element); return array;}
const letters = ['a', 'b', 'c', 'd', 'e'];moveElement(letters, 1, 3); // ['a', 'c', 'd', 'b', 'e']
Sorting and Reversing
Section titled “Sorting and Reversing”const numbers = [3, 1, 4, 1, 5, 9, 2, 6];const strings = ['banana', 'apple', 'cherry', 'date'];
// Basic sortingnumbers.sort(); // [1, 1, 2, 3, 4, 5, 6, 9]strings.sort(); // ['apple', 'banana', 'cherry', 'date']
// Numeric sorting (important!)const nums = [10, 2, 1, 20];nums.sort(); // ['1', '10', '2', '20'] - WRONG!nums.sort((a, b) => a - b); // [1, 2, 10, 20] - Correct
// Custom sorting functionsconst people = [ { name: 'Alice', age: 30, salary: 50000 }, { name: 'Bob', age: 25, salary: 60000 }, { name: 'Charlie', age: 35, salary: 45000 }];
// Sort by age (ascending)people.sort((a, b) => a.age - b.age);
// Sort by name (alphabetical)people.sort((a, b) => a.name.localeCompare(b.name));
// Sort by multiple criteriapeople.sort((a, b) => { // First by age, then by salary if (a.age !== b.age) { return a.age - b.age; } return b.salary - a.salary; // Descending salary});
// Stable sort functionfunction stableSort(array, compareFn) { const indexed = array.map((item, index) => ({ item, index }));
indexed.sort((a, b) => { const result = compareFn(a.item, b.item); return result !== 0 ? result : a.index - b.index; });
return indexed.map(({ item }) => item);}
// Reverse arrayconst original = [1, 2, 3, 4, 5];const reversed = original.reverse(); // [5, 4, 3, 2, 1] - mutates original!
// Non-mutating reverseconst reversedCopy = [...original].reverse();const reversedSlice = original.slice().reverse();
Non-Mutating Methods
Section titled “Non-Mutating Methods”Extraction and Slicing
Section titled “Extraction and Slicing”const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// slice() - Extract portion (doesn't mutate)const subset = arr.slice(2, 6); // [3, 4, 5, 6]const fromIndex = arr.slice(3); // [4, 5, 6, 7, 8, 9, 10]const lastThree = arr.slice(-3); // [8, 9, 10]const copy = arr.slice(); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// Negative indicesconst negativeSlice = arr.slice(-5, -2); // [6, 7, 8]
// concat() - Combine arrays (doesn't mutate)const arr1 = [1, 2, 3];const arr2 = [4, 5, 6];const combined = arr1.concat(arr2); // [1, 2, 3, 4, 5, 6]const multiConcat = arr1.concat(arr2, [7, 8], 9); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
// Spread operator alternativeconst spreadCombined = [...arr1, ...arr2]; // [1, 2, 3, 4, 5, 6]
// join() - Convert to stringconst numbers = [1, 2, 3, 4, 5];const joined = numbers.join(', '); // '1, 2, 3, 4, 5'const path = ['home', 'user', 'documents'].join('/'); // 'home/user/documents'const noSeparator = numbers.join(''); // '12345'
// toString() vs join()console.log(numbers.toString()); // '1,2,3,4,5'console.log(numbers.join()); // '1,2,3,4,5' (same as toString)
Search and Testing Methods
Section titled “Search and Testing Methods”const arr = [1, 2, 3, 4, 3, 5, 6];const people = [ { name: 'Alice', age: 30 }, { name: 'Bob', age: 25 }, { name: 'Charlie', age: 35 }];
// indexOf() and lastIndexOf()const index = arr.indexOf(3); // 2 (first occurrence)const lastIndex = arr.lastIndexOf(3); // 4 (last occurrence)const notFound = arr.indexOf(10); // -1
// includes() - Check if element existsconst hasThree = arr.includes(3); // trueconst hasFromIndex = arr.includes(3, 3); // true (search from index 3)
// find() - Find first matching elementconst person = people.find(p => p.age > 30); // { name: 'Charlie', age: 35 }const notFoundPerson = people.find(p => p.age > 40); // undefined
// findIndex() - Find index of first matching elementconst personIndex = people.findIndex(p => p.name === 'Bob'); // 1const notFoundIndex = people.findIndex(p => p.age > 40); // -1
// findLast() and findLastIndex() - ES2023const lastMatch = arr.findLast(x => x > 3); // 6 (if available)const lastMatchIndex = arr.findLastIndex(x => x > 3); // 6 (if available)
// some() - Test if at least one element passesconst hasAdult = people.some(p => p.age >= 18); // trueconst hasMinor = people.some(p => p.age < 18); // false
// every() - Test if all elements passconst allAdults = people.every(p => p.age >= 18); // trueconst allSeniors = people.every(p => p.age >= 65); // false
// Advanced search with custom predicatesfunction findByProperty(array, property, value) { return array.find(item => item[property] === value);}
function findAllByProperty(array, property, value) { return array.filter(item => item[property] === value);}
function findWithMultipleCriteria(array, criteria) { return array.find(item => Object.keys(criteria).every(key => item[key] === criteria[key]) );}
const employee = findWithMultipleCriteria(people, { name: 'Alice', age: 30 });
Functional Methods
Section titled “Functional Methods”Map, Filter, and Reduce
Section titled “Map, Filter, and Reduce”const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// map() - Transform each elementconst doubled = numbers.map(x => x * 2); // [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]const squared = numbers.map(x => x ** 2); // [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]const strings = numbers.map(x => `Number: ${x}`); // ['Number: 1', 'Number: 2', ...]
// Map with index and array parametersconst withIndex = numbers.map((value, index, array) => ({ value, index, isLast: index === array.length - 1}));
// filter() - Select elements based on conditionconst evens = numbers.filter(x => x % 2 === 0); // [2, 4, 6, 8, 10]const greaterThanFive = numbers.filter(x => x > 5); // [6, 7, 8, 9, 10]
// Complex filteringconst users = [ { name: 'Alice', age: 25, active: true, role: 'admin' }, { name: 'Bob', age: 30, active: false, role: 'user' }, { name: 'Charlie', age: 35, active: true, role: 'user' }, { name: 'Diana', age: 28, active: true, role: 'admin' }];
const activeAdmins = users.filter(user => user.active && user.role === 'admin');const youngUsers = users.filter(user => user.age < 30);
// reduce() - Accumulate valuesconst sum = numbers.reduce((acc, curr) => acc + curr, 0); // 55const product = numbers.reduce((acc, curr) => acc * curr, 1); // 3628800const max = numbers.reduce((acc, curr) => Math.max(acc, curr)); // 10
// Advanced reduce examplesconst groupedUsers = users.reduce((groups, user) => { const key = user.role; if (!groups[key]) { groups[key] = []; } groups[key].push(user); return groups;}, {});
const userStats = users.reduce((stats, user) => { stats.total++; if (user.active) stats.active++; if (user.role === 'admin') stats.admins++; stats.averageAge = (stats.averageAge * (stats.total - 1) + user.age) / stats.total; return stats;}, { total: 0, active: 0, admins: 0, averageAge: 0 });
// reduceRight() - Process from right to leftconst rightToLeft = [1, 2, 3, 4].reduceRight((acc, curr) => acc - curr); // -2
// Implementing map and filter with reducefunction mapWithReduce(array, mapper) { return array.reduce((acc, curr, index, arr) => { acc.push(mapper(curr, index, arr)); return acc; }, []);}
function filterWithReduce(array, predicate) { return array.reduce((acc, curr, index, arr) => { if (predicate(curr, index, arr)) { acc.push(curr); } return acc; }, []);}
Flat and FlatMap
Section titled “Flat and FlatMap”// flat() - Flatten nested arraysconst nested = [[1, 2], [3, 4], [5, 6]];const flattened = nested.flat(); // [1, 2, 3, 4, 5, 6]
const deepNested = [1, [2, [3, [4, 5]]]];const flatLevel1 = deepNested.flat(); // [1, 2, [3, [4, 5]]]const flatLevel2 = deepNested.flat(2); // [1, 2, 3, [4, 5]]const completelyFlat = deepNested.flat(Infinity); // [1, 2, 3, 4, 5]
// flatMap() - Map then flatten (only one level)const words = ['hello', 'world'];const letters = words.flatMap(word => word.split('')); // ['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd']
const sentences = ['Hello world', 'How are you'];const allWords = sentences.flatMap(sentence => sentence.split(' ')); // ['Hello', 'world', 'How', 'are', 'you']
// Complex flatMap exampleconst users = [ { name: 'Alice', hobbies: ['reading', 'swimming'] }, { name: 'Bob', hobbies: ['gaming', 'cooking', 'reading'] }, { name: 'Charlie', hobbies: ['swimming', 'hiking'] }];
const allHobbies = users.flatMap(user => user.hobbies);const uniqueHobbies = [...new Set(allHobbies)];
// Custom flatten function for deeper controlfunction flattenDeep(arr) { return Array.isArray(arr) ? arr.reduce((acc, val) => acc.concat(flattenDeep(val)), []) : [arr];}
function flattenToDepth(arr, depth = 1) { if (depth <= 0) return arr; return arr.reduce((acc, val) => Array.isArray(val) ? acc.concat(flattenToDepth(val, depth - 1)) : acc.concat(val), [] );}
Advanced Array Techniques
Section titled “Advanced Array Techniques”Array Comprehensions and Pipelines
Section titled “Array Comprehensions and Pipelines”// Method chaining for complex operationsconst numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const result = numbers .filter(x => x % 2 === 0) // [2, 4, 6, 8, 10] .map(x => x ** 2) // [4, 16, 36, 64, 100] .filter(x => x > 20) // [36, 64, 100] .reduce((sum, x) => sum + x, 0); // 200
// Complex data transformation pipelineconst salesData = [ { region: 'North', sales: [100, 200, 150], quarter: 'Q1' }, { region: 'South', sales: [80, 120, 90], quarter: 'Q1' }, { region: 'North', sales: [180, 220, 200], quarter: 'Q2' }, { region: 'South', sales: [95, 110, 85], quarter: 'Q2' }];
const analysis = salesData .map(item => ({ ...item, total: item.sales.reduce((sum, sale) => sum + sale, 0), average: item.sales.reduce((sum, sale) => sum + sale, 0) / item.sales.length })) .filter(item => item.total > 250) .sort((a, b) => b.total - a.total) .map(item => ({ region: item.region, quarter: item.quarter, performance: item.total > 400 ? 'Excellent' : 'Good' }));
// Functional composition helpersconst pipe = (...functions) => (value) => functions.reduce((acc, fn) => fn(acc), value);
const compose = (...functions) => (value) => functions.reduceRight((acc, fn) => fn(acc), value);
// Usageconst transformNumbers = pipe( arr => arr.filter(x => x > 0), arr => arr.map(x => x * 2), arr => arr.sort((a, b) => a - b));
const transformed = transformNumbers([-1, 3, -2, 5, 1]);
Array Utilities and Helpers
Section titled “Array Utilities and Helpers”// Array equality comparisonfunction arrayEquals(a, b) { if (a.length !== b.length) return false; return a.every((val, index) => val === b[index]);}
function deepArrayEquals(a, b) { if (a.length !== b.length) return false; return a.every((val, index) => { if (Array.isArray(val) && Array.isArray(b[index])) { return deepArrayEquals(val, b[index]); } return val === b[index]; });}
// Array intersection, union, differencefunction intersection(arr1, arr2) { return arr1.filter(x => arr2.includes(x));}
function union(arr1, arr2) { return [...new Set([...arr1, ...arr2])];}
function difference(arr1, arr2) { return arr1.filter(x => !arr2.includes(x));}
function symmetricDifference(arr1, arr2) { return [ ...arr1.filter(x => !arr2.includes(x)), ...arr2.filter(x => !arr1.includes(x)) ];}
// Chunk array into smaller arraysfunction chunk(array, size) { const chunks = []; for (let i = 0; i < array.length; i += size) { chunks.push(array.slice(i, i + size)); } return chunks;}
// Shuffle array (Fisher-Yates algorithm)function shuffle(array) { const shuffled = [...array]; for (let i = shuffled.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]]; } return shuffled;}
// Sample random elementsfunction sample(array, n = 1) { const shuffled = shuffle(array); return n === 1 ? shuffled[0] : shuffled.slice(0, n);}
// Partition array based on predicatefunction partition(array, predicate) { const passed = []; const failed = [];
array.forEach(item => { if (predicate(item)) { passed.push(item); } else { failed.push(item); } });
return [passed, failed];}
// Group consecutive elementsfunction groupConsecutive(array, keyFn = x => x) { const groups = []; let currentGroup = []; let lastKey = Symbol('initial');
for (const item of array) { const key = keyFn(item); if (key !== lastKey) { if (currentGroup.length > 0) { groups.push(currentGroup); } currentGroup = [item]; lastKey = key; } else { currentGroup.push(item); } }
if (currentGroup.length > 0) { groups.push(currentGroup); }
return groups;}
// Usage examplesconsole.log(intersection([1, 2, 3], [2, 3, 4])); // [2, 3]console.log(union([1, 2, 3], [2, 3, 4])); // [1, 2, 3, 4]console.log(difference([1, 2, 3], [2, 3, 4])); // [1]console.log(symmetricDifference([1, 2, 3], [2, 3, 4])); // [1, 4]console.log(chunk([1, 2, 3, 4, 5, 6, 7], 3)); // [[1, 2, 3], [4, 5, 6], [7]]console.log(sample([1, 2, 3, 4, 5], 3)); // Random 3 elementsconsole.log(partition([1, 2, 3, 4, 5], x => x % 2 === 0)); // [[2, 4], [1, 3, 5]]
This comprehensive guide covers the vast majority of array operations and techniques in JavaScript. Arrays are incredibly powerful and versatile, and mastering these methods will significantly improve your JavaScript programming skills.
Practice these array methods and patterns to become proficient in JavaScript data manipulation.