📋 Arrays

Working with Collections

Arrays in JavaScript

Arrays are ordered collections of values. They're versatile data structures for storing and manipulating lists of data efficiently.

📝 Creating Arrays

// Array literal (preferred)
let fruits = ['apple', 'banana', 'orange'];
let numbers = [1, 2, 3, 4, 5];
let mixed = [1, 'hello', true, null, { name: 'John' }];

// Array constructor
let arr1 = new Array(3);        // [empty × 3]
let arr2 = new Array(1, 2, 3);  // [1, 2, 3]

// Array.of() - creates array from arguments
let arr3 = Array.of(5);         // [5] (not [empty × 5])
let arr4 = Array.of(1, 2, 3);   // [1, 2, 3]

// Array.from() - create from array-like or iterable
let str = 'hello';
let chars = Array.from(str);    // ['h', 'e', 'l', 'l', 'o']

let range = Array.from({ length: 5 }, (_, i) => i);
console.log(range);  // [0, 1, 2, 3, 4]

// Spread operator
let original = [1, 2, 3];
let copy = [...original];       // [1, 2, 3]
let combined = [...original, 4, 5];  // [1, 2, 3, 4, 5]

🔍 Accessing Elements

let fruits = ['apple', 'banana', 'orange', 'grape', 'mango'];

// By index (zero-based)
console.log(fruits[0]);   // 'apple'
console.log(fruits[2]);   // 'orange'
console.log(fruits[10]);  // undefined

// Negative indexing with at() (ES2022)
console.log(fruits.at(0));   // 'apple'
console.log(fruits.at(-1));  // 'mango' (last item)
console.log(fruits.at(-2));  // 'grape'

// First and last
let first = fruits[0];
let last = fruits[fruits.length - 1];
// Or: let last = fruits.at(-1);

// Length property
console.log(fruits.length);  // 5

// Modifying by index
fruits[1] = 'blueberry';
console.log(fruits);  // ['apple', 'blueberry', 'orange', 'grape', 'mango']

// Adding beyond length creates sparse array
fruits[10] = 'kiwi';
console.log(fruits.length);  // 11
console.log(fruits[5]);      // undefined

➕ Adding and Removing Elements

End of Array

let numbers = [1, 2, 3];

// push - add to end (mutates, returns new length)
numbers.push(4);
console.log(numbers);  // [1, 2, 3, 4]

numbers.push(5, 6, 7);
console.log(numbers);  // [1, 2, 3, 4, 5, 6, 7]

// pop - remove from end (mutates, returns removed element)
let last = numbers.pop();
console.log(last);     // 7
console.log(numbers);  // [1, 2, 3, 4, 5, 6]

Beginning of Array

let numbers = [1, 2, 3];

// unshift - add to beginning (mutates, returns new length)
numbers.unshift(0);
console.log(numbers);  // [0, 1, 2, 3]

numbers.unshift(-2, -1);
console.log(numbers);  // [-2, -1, 0, 1, 2, 3]

// shift - remove from beginning (mutates, returns removed element)
let first = numbers.shift();
console.log(first);    // -2
console.log(numbers);  // [-1, 0, 1, 2, 3]

Middle of Array

let fruits = ['apple', 'banana', 'orange'];

// splice(start, deleteCount, ...items)
// Remove 1 element at index 1
fruits.splice(1, 1);
console.log(fruits);  // ['apple', 'orange']

// Add elements at index 1
fruits.splice(1, 0, 'grape', 'mango');
console.log(fruits);  // ['apple', 'grape', 'mango', 'orange']

// Replace elements
fruits.splice(1, 2, 'kiwi');
console.log(fruits);  // ['apple', 'kiwi', 'orange']

// Remove from index to end
let removed = fruits.splice(1);
console.log(removed);  // ['kiwi', 'orange']
console.log(fruits);   // ['apple']

🔄 Array Methods - Iteration

forEach

// Execute function for each element
let numbers = [1, 2, 3, 4, 5];

numbers.forEach((num) => {
    console.log(num * 2);
});

// With index and array
numbers.forEach((num, index, arr) => {
    console.log(`Index ${index}: ${num}`);
});

// Note: forEach cannot be stopped (no break/return)
// Returns undefined

map

// Transform each element, returns new array
let numbers = [1, 2, 3, 4, 5];

let doubled = numbers.map(n => n * 2);
console.log(doubled);  // [2, 4, 6, 8, 10]

let squared = numbers.map(n => n ** 2);
console.log(squared);  // [1, 4, 9, 16, 25]

// With objects
let users = [
    { name: 'John', age: 25 },
    { name: 'Jane', age: 30 }
];

let names = users.map(user => user.name);
console.log(names);  // ['John', 'Jane']

// With index
let indexed = numbers.map((n, i) => `${i}: ${n}`);
console.log(indexed);  // ['0: 1', '1: 2', '2: 3', '3: 4', '4: 5']

filter

// Keep elements that pass test, returns new array
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

let evens = numbers.filter(n => n % 2 === 0);
console.log(evens);  // [2, 4, 6, 8, 10]

let greaterThanFive = numbers.filter(n => n > 5);
console.log(greaterThanFive);  // [6, 7, 8, 9, 10]

// With objects
let users = [
    { name: 'John', age: 25, active: true },
    { name: 'Jane', age: 30, active: false },
    { name: 'Bob', age: 20, active: true }
];

let activeUsers = users.filter(user => user.active);
console.log(activeUsers);  // John and Bob

let adults = users.filter(user => user.age >= 25);
console.log(adults);  // John and Jane

reduce

// Reduce array to single value
let numbers = [1, 2, 3, 4, 5];

// Sum
let sum = numbers.reduce((acc, n) => acc + n, 0);
console.log(sum);  // 15

// Product
let product = numbers.reduce((acc, n) => acc * n, 1);
console.log(product);  // 120

// Maximum value
let max = numbers.reduce((acc, n) => Math.max(acc, n));
console.log(max);  // 5

// Count occurrences
let items = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple'];
let counts = items.reduce((acc, item) => {
    acc[item] = (acc[item] || 0) + 1;
    return acc;
}, {});
console.log(counts);  // { apple: 3, banana: 2, orange: 1 }

// Group by property
let users = [
    { name: 'John', role: 'admin' },
    { name: 'Jane', role: 'user' },
    { name: 'Bob', role: 'admin' }
];

let grouped = users.reduce((acc, user) => {
    if (!acc[user.role]) acc[user.role] = [];
    acc[user.role].push(user);
    return acc;
}, {});
console.log(grouped);
// { admin: [John, Bob], user: [Jane] }

// reduceRight - process from right to left
let reversed = numbers.reduceRight((acc, n) => {
    acc.push(n);
    return acc;
}, []);
console.log(reversed);  // [5, 4, 3, 2, 1]

🔎 Searching and Testing

find and findIndex

let numbers = [1, 5, 10, 15, 20];

// find - returns first element that passes test
let found = numbers.find(n => n > 10);
console.log(found);  // 15

// findIndex - returns index of first match
let index = numbers.findIndex(n => n > 10);
console.log(index);  // 3

// findLast and findLastIndex (ES2023)
let last = numbers.findLast(n => n > 10);
console.log(last);  // 20

let lastIndex = numbers.findLastIndex(n => n > 10);
console.log(lastIndex);  // 4

// With objects
let users = [
    { id: 1, name: 'John' },
    { id: 2, name: 'Jane' },
    { id: 3, name: 'Bob' }
];

let user = users.find(u => u.id === 2);
console.log(user);  // { id: 2, name: 'Jane' }

includes, indexOf, lastIndexOf

let fruits = ['apple', 'banana', 'orange', 'banana', 'grape'];

// includes - check if element exists (ES2016)
console.log(fruits.includes('banana'));  // true
console.log(fruits.includes('kiwi'));    // false

// indexOf - first index of element (-1 if not found)
console.log(fruits.indexOf('banana'));   // 1
console.log(fruits.indexOf('kiwi'));     // -1

// lastIndexOf - last index of element
console.log(fruits.lastIndexOf('banana')); // 3

// With start position
console.log(fruits.indexOf('banana', 2));  // 3 (search from index 2)

some and every

let numbers = [1, 2, 3, 4, 5];

// some - test if ANY element passes
console.log(numbers.some(n => n > 3));   // true
console.log(numbers.some(n => n > 10));  // false

// every - test if ALL elements pass
console.log(numbers.every(n => n > 0));  // true
console.log(numbers.every(n => n > 3));  // false

// Practical examples
let users = [
    { name: 'John', age: 25 },
    { name: 'Jane', age: 17 },
    { name: 'Bob', age: 30 }
];

let hasMinor = users.some(u => u.age < 18);
console.log(hasMinor);  // true

let allAdults = users.every(u => u.age >= 18);
console.log(allAdults);  // false

✂️ Slicing and Joining

slice

// Extract portion (doesn't mutate original)
let fruits = ['apple', 'banana', 'orange', 'grape', 'mango'];

// slice(start, end) - end not included
let sliced = fruits.slice(1, 3);
console.log(sliced);  // ['banana', 'orange']
console.log(fruits);  // Original unchanged

// From index to end
console.log(fruits.slice(2));  // ['orange', 'grape', 'mango']

// Negative indices (from end)
console.log(fruits.slice(-2));    // ['grape', 'mango']
console.log(fruits.slice(1, -1)); // ['banana', 'orange', 'grape']

// Copy array
let copy = fruits.slice();
// Or: let copy = [...fruits];

concat

// Merge arrays (doesn't mutate originals)
let arr1 = [1, 2, 3];
let arr2 = [4, 5, 6];
let arr3 = [7, 8, 9];

let merged = arr1.concat(arr2);
console.log(merged);  // [1, 2, 3, 4, 5, 6]

// Multiple arrays
let all = arr1.concat(arr2, arr3);
console.log(all);  // [1, 2, 3, 4, 5, 6, 7, 8, 9]

// With values
let extended = arr1.concat(4, 5, [6, 7]);
console.log(extended);  // [1, 2, 3, 4, 5, 6, 7]

// Modern alternative: spread
let spread = [...arr1, ...arr2, ...arr3];
console.log(spread);  // [1, 2, 3, 4, 5, 6, 7, 8, 9]

join and split

// join - array to string
let fruits = ['apple', 'banana', 'orange'];

console.log(fruits.join());       // 'apple,banana,orange'
console.log(fruits.join(', '));   // 'apple, banana, orange'
console.log(fruits.join(' - '));  // 'apple - banana - orange'
console.log(fruits.join(''));     // 'applebananaorange'

// split - string to array (String method)
let text = 'apple,banana,orange';
let arr = text.split(',');
console.log(arr);  // ['apple', 'banana', 'orange']

let sentence = 'Hello World JavaScript';
let words = sentence.split(' ');
console.log(words);  // ['Hello', 'World', 'JavaScript']

let chars = 'hello'.split('');
console.log(chars);  // ['h', 'e', 'l', 'l', 'o']

🔀 Sorting and Reversing

// reverse - reverses array (mutates)
let numbers = [1, 2, 3, 4, 5];
numbers.reverse();
console.log(numbers);  // [5, 4, 3, 2, 1]

// toReversed - returns new reversed array (ES2023)
let original = [1, 2, 3];
let reversed = original.toReversed();
console.log(original);  // [1, 2, 3] (unchanged)
console.log(reversed);  // [3, 2, 1]

// sort - sorts array (mutates)
let fruits = ['banana', 'apple', 'orange', 'grape'];
fruits.sort();
console.log(fruits);  // ['apple', 'banana', 'grape', 'orange']

// Sort numbers (default converts to strings!)
let nums = [10, 5, 40, 25, 1000, 1];
nums.sort();
console.log(nums);  // [1, 10, 1000, 25, 40, 5] (wrong!)

// Proper numeric sort
nums.sort((a, b) => a - b);  // Ascending
console.log(nums);  // [1, 5, 10, 25, 40, 1000]

nums.sort((a, b) => b - a);  // Descending
console.log(nums);  // [1000, 40, 25, 10, 5, 1]

// Sort objects
let users = [
    { name: 'John', age: 30 },
    { name: 'Jane', age: 25 },
    { name: 'Bob', age: 35 }
];

// By age
users.sort((a, b) => a.age - b.age);
console.log(users);  // Jane(25), John(30), Bob(35)

// By name
users.sort((a, b) => a.name.localeCompare(b.name));
console.log(users);  // Bob, Jane, John

// toSorted - returns new sorted array (ES2023)
let original2 = [3, 1, 4, 1, 5];
let sorted = original2.toSorted((a, b) => a - b);
console.log(original2);  // [3, 1, 4, 1, 5] (unchanged)
console.log(sorted);     // [1, 1, 3, 4, 5]

🎯 Advanced Array Methods

flat and flatMap

// flat - flatten nested arrays (ES2019)
let nested = [1, [2, 3], [4, [5, 6]]];

console.log(nested.flat());     // [1, 2, 3, 4, [5, 6]] (1 level)
console.log(nested.flat(2));    // [1, 2, 3, 4, 5, 6] (2 levels)
console.log(nested.flat(Infinity)); // Fully flatten

// flatMap - map then flat (1 level)
let numbers = [1, 2, 3];
let doubled = numbers.flatMap(n => [n, n * 2]);
console.log(doubled);  // [1, 2, 2, 4, 3, 6]

// Practical: split sentences to words
let sentences = ['Hello world', 'JavaScript is fun'];
let words = sentences.flatMap(s => s.split(' '));
console.log(words);  // ['Hello', 'world', 'JavaScript', 'is', 'fun']

fill and copyWithin

// fill - fill with static value (mutates)
let arr1 = [1, 2, 3, 4, 5];
arr1.fill(0);
console.log(arr1);  // [0, 0, 0, 0, 0]

// fill(value, start, end)
let arr2 = [1, 2, 3, 4, 5];
arr2.fill(0, 2, 4);
console.log(arr2);  // [1, 2, 0, 0, 5]

// Create array with initial value
let zeros = new Array(5).fill(0);
console.log(zeros);  // [0, 0, 0, 0, 0]

// copyWithin - copy part of array (mutates)
let arr3 = [1, 2, 3, 4, 5];
arr3.copyWithin(0, 3);  // Copy from index 3 to index 0
console.log(arr3);  // [4, 5, 3, 4, 5]

Array.isArray

// Check if value is array
console.log(Array.isArray([1, 2, 3]));    // true
console.log(Array.isArray('hello'));      // false
console.log(Array.isArray({ a: 1 }));     // false
console.log(Array.isArray(null));         // false

// Why not typeof?
console.log(typeof [1, 2, 3]);  // 'object' (not helpful!)

// Practical: input validation
function processArray(input) {
    if (!Array.isArray(input)) {
        throw new Error('Input must be an array');
    }
    return input.map(n => n * 2);
}

💡 Practical Examples

Remove Duplicates

// Using Set
let numbers = [1, 2, 2, 3, 3, 3, 4, 5, 5];
let unique = [...new Set(numbers)];
console.log(unique);  // [1, 2, 3, 4, 5]

// Using filter
let unique2 = numbers.filter((n, i, arr) => arr.indexOf(n) === i);
console.log(unique2);  // [1, 2, 3, 4, 5]

// Objects by property
let users = [
    { id: 1, name: 'John' },
    { id: 2, name: 'Jane' },
    { id: 1, name: 'John' }
];

let uniqueUsers = users.filter((u, i, arr) => 
    arr.findIndex(user => user.id === u.id) === i
);

Chunk Array

// Split array into chunks
function chunk(arr, size) {
    return Array.from({ length: Math.ceil(arr.length / size) }, (_, i) =>
        arr.slice(i * size, i * size + size)
    );
}

let numbers = [1, 2, 3, 4, 5, 6, 7, 8];
console.log(chunk(numbers, 3));
// [[1, 2, 3], [4, 5, 6], [7, 8]]

Shuffle Array

// Fisher-Yates shuffle
function shuffle(arr) {
    let shuffled = [...arr];
    for (let i = shuffled.length - 1; i > 0; i--) {
        let j = Math.floor(Math.random() * (i + 1));
        [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
    }
    return shuffled;
}

let cards = [1, 2, 3, 4, 5];
console.log(shuffle(cards));  // Random order

Pagination

function paginate(arr, page, perPage) {
    const start = (page - 1) * perPage;
    const end = start + perPage;
    return {
        data: arr.slice(start, end),
        page: page,
        perPage: perPage,
        total: arr.length,
        totalPages: Math.ceil(arr.length / perPage)
    };
}

let items = Array.from({ length: 25 }, (_, i) => i + 1);
console.log(paginate(items, 2, 10));
// { data: [11-20], page: 2, perPage: 10, total: 25, totalPages: 3 }

Array Statistics

function getStats(arr) {
    const sum = arr.reduce((acc, n) => acc + n, 0);
    const avg = sum / arr.length;
    const sorted = [...arr].sort((a, b) => a - b);
    const min = sorted[0];
    const max = sorted[sorted.length - 1];
    const median = sorted[Math.floor(sorted.length / 2)];
    
    return { sum, avg, min, max, median };
}

let scores = [85, 92, 78, 95, 88];
console.log(getStats(scores));
// { sum: 438, avg: 87.6, min: 78, max: 95, median: 88 }

🎯 Key Takeaways