JavaScript Arrays

Arrays in JavaScript are a fundamental data structure used to store lists of values. Arrays can hold elements of any data type, including numbers, strings, objects, and even other arrays. They are zero-indexed, meaning the first element has an index of 0.

Concept and Use Cases

Definition: A JavaScript array is an ordered, mutable collection of values, where each value is identified by an index. Arrays can grow and shrink dynamically, and they come with a rich set of methods for performing various operations.

Common Use Cases:

  • Storing lists of items (e.g., a list of names, numbers).
  • Representing collections of data in applications.
  • Implementing data structures like stacks and queues.
  • Performing operations like sorting, filtering, and mapping.

When to Use

  • When you need to store multiple values in a single variable.
  • When the order of elements is important.
  • When you need to perform operations on collections of data.

Time and Space Complexity

Time Complexity:

  • Access: O(1) (constant time access to elements by index)
  • Insertion/Deletion at the end: O(1)
  • Insertion/Deletion at the beginning: O(n) (requires shifting elements)
  • Searching: O(n) (linear search)

Space Complexity:

  • O(n) (proportional to the number of elements in the array)

Array Operations and Methods

Creating Arrays

Example:

let emptyArray = [];
let numberArray = [1, 2, 3, 4, 5];
let mixedArray = [1, 'two', {three: 3}, [4, 5]];
let arrayWithConstructor = new Array(10);  // Creates an array with 10 empty slots

Accessing Elements

Example:

let arr = [10, 20, 30, 40, 50];
console.log(arr[0]);  // Output: 10
console.log(arr[3]);  // Output: 40

Modifying Elements

Example:

let arr = [1, 2, 3];
arr[0] = 10;
arr[2] = 30;
console.log(arr);  // Output: [10, 2, 30]

Adding and Removing Elements

Example:

let arr = [1, 2, 3];
arr.push(4);  // Adds to the end
console.log(arr);  // Output: [1, 2, 3, 4]

arr.pop();  // Removes from the end
console.log(arr);  // Output: [1, 2, 3]

arr.unshift(0);  // Adds to the beginning
console.log(arr);  // Output: [0, 1, 2, 3]

arr.shift();  // Removes from the beginning
console.log(arr);  // Output: [1, 2, 3]

Array Length

Example:

let arr = [1, 2, 3];
console.log(arr.length);  // Output: 3
arr.length = 5;  // Resizes the array
console.log(arr);  // Output: [1, 2, 3, <2 empty slots>]

Iterating Over Arrays

Example:

let arr = [1, 2, 3, 4, 5];
for (let i = 0; i < arr.length; i++) {
    console.log(arr[i]);
}

arr.forEach((element, index) => {
    console.log(element, index);
});

Array Methods

Example:

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

// Map
let doubled = arr.map(x => x * 2);
console.log(doubled);  // Output: [2, 4, 6, 8, 10]

// Filter
let evens = arr.filter(x => x % 2 === 0);
console.log(evens);  // Output: [2, 4]

// Reduce
let sum = arr.reduce((acc, x) => acc + x, 0);
console.log(sum);  // Output: 15

// Find
let firstEven = arr.find(x => x % 2 === 0);
console.log(firstEven);  // Output: 2

// Some
let hasEven = arr.some(x => x % 2 === 0);
console.log(hasEven);  // Output: true

// Every
let allEven = arr.every(x => x % 2 === 0);
console.log(allEven);  // Output: false

// Slice
let subArray = arr.slice(1, 3);
console.log(subArray);  // Output: [2, 3]

// Splice
arr.splice(2, 1, 'a', 'b');
console.log(arr);  // Output: [1, 2, 'a', 'b', 4, 5]

// Concat
let arr2 = [6, 7, 8];
let concatenated = arr.concat(arr2);
console.log(concatenated);  // Output: [1, 2, 'a', 'b', 4, 5, 6, 7, 8]

Practical Tips and Tricks

  • Using Array.from and Array.of: Create arrays from array-like objects or individual elements.

    Example:

    let str = 'hello';
    let arr = Array.from(str);
    console.log(arr);  // Output: ['h', 'e', 'l', 'l', 'o']
    
    let arr2 = Array.of(1, 2, 3);
    console.log(arr2);  // Output: [1, 2, 3]
    
  • Filling Arrays: Use fill to initialize or reset arrays.

    Example:

    let arr = new Array(5).fill(0);
    console.log(arr);  // Output: [0, 0, 0, 0, 0]
    
  • Flattening Arrays: Use flat to flatten nested arrays.

    Example:

    let nestedArr = [1, [2, [3, 4], 5]];
    let flatArr = nestedArr.flat(2);
    console.log(flatArr);  // Output: [1, 2, 3, 4, 5]
    
  • Removing Duplicates: Use Set to remove duplicates from an array.

    Example:

    let arr = [1, 2, 2, 3, 3, 4];
    let uniqueArr = Array.from(new Set(arr));
    console.log(uniqueArr);  // Output: [1, 2, 3, 4]
    

Common Gotchas

  • Sparse Arrays: Assigning to indices beyond the current length can create sparse arrays.

    Example:

    let arr = [1, 2, 3];
    arr[10] = 11;
    console.log(arr);  // Output: [1, 2, 3, <7 empty slots>, 11]
    
  • Array-Like Objects: Objects like arguments and DOM NodeLists are not true arrays but can be converted.

    Example:

    function example() {
        let args = Array.from(arguments);
        console.log(args);
    }
    example(1, 2, 3);  // Output: [1, 2, 3]
    
  • Mutating Methods: Methods like splice, sort, and reverse mutate the original array.

    Example:

    let arr = [1, 2, 3];
    arr.reverse();
    console.log(arr);  // Output: [3, 2, 1]
    

Advanced Topics

Typed Arrays

Typed Arrays provide a way to handle binary data directly in JavaScript. They are used in scenarios like working with raw binary data or interacting with Web APIs.

Example:

let buffer = new ArrayBuffer(16);
let int32View = new Int32Array(buffer);
int32View[0] = 42;
console.log(int32View);  // Output: Int32Array [ 42, 0, 0, 0 ]

ArrayBuffer and DataView

ArrayBuffer is a generic, fixed-length binary data buffer, and DataView provides a low-level interface for reading and writing multiple number types in an ArrayBuffer.

Example:

let buffer = new ArrayBuffer(16);
let view = new DataView(buffer);
view.setInt8(0, 127);
console.log(view.getInt8(0));  // Output: 127

Advanced Array Methods

Example:

// FlatMap
let arr = [1, 2, 3, 4];
let result = arr.flatMap(x => [x, x * 2]);
console.log(result);  // Output: [1, 2, 2, 4, 3, 6, 4, 8]

// ReduceRight
let arr2 = [1, 2, 3, 4];
let result2 = arr2.reduceRight((acc, x) => acc - x, 0);
console.log(result2);  // Output: -10

// Entries, Keys, Values
let arr3 = ['a', 'b', 'c'];
for (let [index, element] of arr3.entries()) {
    console.log(index, element);
}
for (let key of arr3.keys()) {
    console.log(key);
}
for (let value of arr3.values()) {
    console.log(value);
}

Array Algorithms

Below are some common array algorithms you should be familiar with:

Sorting

Sorting an array involves arranging the elements in a specific order, typically ascending or descending.

Example:

let arr = [3, 1, 4, 1, 5, 9];
arr.sort((a, b) => a - b);
console.log(arr);  // Output: [1, 1, 3, 4, 5, 9]

Searching

Searching an array is about finding elements that meet certain criteria.

Example:

let arr = [10, 20, 30, 40, 50];
let found = arr.find(x => x > 25);
console.log(found);  // Output: 30

Merging Arrays

Merging arrays involves combining two or more arrays into one.

Example:

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

Reversing Arrays

Reversing an array changes the order of its elements to the opposite direction.

Example:

let arr = [1, 2, 3];
arr.reverse();
console.log(arr);  // Output: [3, 2, 1]

Rotating Arrays

Rotating an array shifts its elements to the left or right by a specified number of positions.

Example:

function rotateArray(arr, k) {
    k = k % arr.length;
    return [...arr.slice(-k), ...arr.slice(0, -k)];
}

let arr = [1, 2, 3, 4, 5];
console.log(rotateArray(arr, 2));  // Output: [4, 5, 1, 2, 3]

Interview Tips and Tricks

  • Understand Array Mutability: Know which methods mutate the array and which return a new array. This is crucial for writing efficient and bug-free code.

  • Master Higher-Order Functions: Familiarize yourself with map, filter, reduce, and other higher-order functions. These are often used in interview problems.

  • Practice Common Algorithms: Be comfortable with algorithms involving arrays, such as searching, sorting, and manipulating subarrays.

  • Edge Cases: Always consider edge cases like empty arrays, arrays with a single element, and arrays with duplicate values.

Common Mistakes

  • Off-by-One Errors: Be cautious with indices, especially in loops and when slicing arrays.

  • Mutating Arrays Unintentionally: Understand when methods like splice, sort, and reverse modify the original array.

  • Incorrect Use of Higher-Order Functions: Misunderstanding the behavior of map, filter, and reduce can lead to logic errors in your code.

  • Not Handling Sparse Arrays Properly: Be aware of the implications of creating sparse arrays, especially when using methods like Array with a constructor argument.

By mastering JavaScript arrays and understanding their intricacies, you will be well-equipped to handle a variety of interview questions and real-world problems involving collections of data. Regular practice and a solid grasp of advanced topics will deepen your understanding and improve your problem-solving skills.

Practice Problems

Given the prices of a single stock over time, find the optimal day to buy and sell the stock to maximize profit while avoiding losses.

function maxProfit(prices: number[]): number {
    let ans = 0;
    let mi = prices[0];
    for (const v of prices) {
        ans = Math.max(ans, v - mi);
        mi = Math.min(mi, v);
    }
    return ans;
}
Container With Most WaterDifficulty: Medium

Given two pointers representing the start and end of a container, find the maximum area that can be trapped between the two "walls" represented by the pointer positions.

function maxArea(height: number[]): number {
    let i = 0;
    let j = height.length - 1;
    let ans = 0;
    while (i < j) {
        const t = Math.min(height[i], height[j]) * (j - i);
        ans = Math.max(ans, t);
        if (height[i] < height[j]) {
            ++i;
        } else {
            --j;
        }
    }
    return ans;
}
Sort ColorsDifficulty: Medium

The task is to efficiently sort an array of colored integers, where each integer represents the color with values ranging from 0 (black) to 2 (white), in ascending order of their corresponding colors.

/**
 Do not return anything, modify nums in-place instead.
 */
function sortColors(nums: number[]): void {
    let i = -1;
    let j = nums.length;
    let k = 0;
    while (k < j) {
        if (nums[k] === 0) {
            ++i;
            [nums[i], nums[k]] = [nums[k], nums[i]];
            ++k;
        } else if (nums[k] === 2) {
            --j;
            [nums[j], nums[k]] = [nums[k], nums[j]];
        } else {
            ++k;
        }
    }
}

Write an algorithm to calculate the product of all numbers in an array, excluding the number at each index, for a given input array of integers.

function productExceptSelf(nums: number[]): number[] {
    return nums.map((_, i) => nums.reduce((pre, val, j) => pre * (i === j ? 1 : val), 1));
}
Subarray Sum Equals KDifficulty: Medium

Given an array and an integer target sum, find all unique subarrays within the array that sum up to the target value.

function subarraySum(nums: number[], k: number): number {
    const cnt: Map<number, number> = new Map();
    cnt.set(0, 1);
    let [ans, s] = [0, 0];
    for (const x of nums) {
        s += x;
        ans += cnt.get(s - k) || 0;
        cnt.set(s, (cnt.get(s) || 0) + 1);
    }
    return ans;
}

Let's continue exploring the next page. Take your time, and proceed when you're ready.

Lesson completed?

Found a bug, typo, or have feedback?

Let me know