Programming Fundamentals

Arrays - Working with Lists

3 min read
Focus: PROGRAMMING-FUNDAMENTALS

TL;DR — Quick Summary

  • Prefer non-mutating methods (map, filter, slice, spread) — avoid mutating shared arrays unexpectedly.
  • Always use a comparator with sort(): (a, b) => a - b — the default lexicographic sort produces wrong results for numbers.
  • Use arr.at(-1) to access the last element — much cleaner than arr[arr.length - 1].
  • Destructuring and spread are fundamental in modern JavaScript — master them for cleaner, more expressive code.

Lesson Overview

Arrays are ordered, indexed lists — the most fundamental data structure in programming. Almost every real application involves arrays: a list of users, a shopping cart, search results, messages, notifications. Mastering array manipulation is non-negotiable.

JavaScript arrays are dynamic (grow/shrink at runtime), zero-indexed, and can hold mixed types (though you should avoid this in practice). They provide a rich set of built-in methods, many of which were covered in Loops — here we go deeper into mutation vs. immutability, destructuring, spreading, and advanced patterns used in real codebases.

Conceptual Deep Dive

Creation and access: Arrays are created with [] or Array.from(). Elements are accessed by index starting at 0. The last element is at arr[arr.length - 1] or arr.at(-1).

Mutating methods (modify the original array):

  • push / pop: add/remove from end
  • unshift / shift: add/remove from start
  • splice(index, deleteCount, ...items): insert/remove at any position
  • sort: sort in place (use a comparator function!)
  • reverse: reverse in place
  • fill: fill with a value

Non-mutating methods (return new arrays — prefer these):

  • slice(start, end): copy a portion
  • concat: join arrays
  • map, filter, flat, flatMap: transform
  • [...arr] or Array.from(arr): shallow copy

Destructuring and spread/rest are modern syntax for clean array handling.

Implementation Lab

Array Creation and Core Methods
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// Creation
const fruits = ['apple', 'banana', 'cherry'];
const zeros = new Array(5).fill(0); // [0, 0, 0, 0, 0]0, 0, 0, 0, 0]
const range = Array.from({ length: 5 }, (_, i) => i + 1); // [1, 2, 3, 4, 5]1, 2, 3, 4, 5]
 
// Access
console.log(fruits[0]);        // 'apple'
console.log(fruits.at(-1));    // 'cherry' (last element)(last element)
console.log(fruits.length);    // 3
 
// ✅ Mutating methods
const cart = ['laptop'];
cart.push('phone', 'tablet'); // add to end → ['laptop', 'phone', 'tablet']'laptop', 'phone', 'tablet']
cart.pop();                    // remove from end → ['laptop', 'phone']'laptop', 'phone']
cart.unshift('charger');       // add to start → ['charger', 'laptop', 'phone']'charger', 'laptop', 'phone']
cart.shift();                  // remove from start → ['laptop', 'phone']'laptop', 'phone']
 
// splice: insert/remove at any index
const items = ['a', 'b', 'c', 'd'];
const removed = items.splice(1, 2, 'x', 'y'); // at index 1, remove 2, insert x, y2, insert x, y
console.log(items);   // ['a', 'x', 'y', 'd']'a', 'x', 'y', 'd']
console.log(removed); // ['b', 'c']'b', 'c']
 
// slice: copy without modifying original
const letters = ['a', 'b', 'c', 'd', 'e'];
console.log(letters.slice(1, 3));  // ['b', 'c'] (index 1 to 3, not including 3)'b', 'c'] (index 1 to 3, not including 3)
console.log(letters.slice(-2));    // ['d', 'e'] (last 2)'d', 'e'] (last 2)
console.log(letters);              // unchanged!
 
// Searching
console.log(fruits.includes('banana'));   // true
console.log(fruits.indexOf('cherry'));    // 2 (index, or -1 if not found)(index, or -1 if not found)
console.log(fruits.find(f => f.startsWith('a'))); // 'apple'
Sorting, Spreading, and Destructuring
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// ⚠️ sort() without comparator: converts to string first (bug!)) without comparator: converts to string first (bug!)
const nums = [10, 1, 21, 2];
console.log(nums.sort());           // [1, 10, 2, 21] ❌ lexicographic1, 10, 2, 21] ❌ lexicographic
console.log(nums.sort((a, b) => a - b)); // [1, 2, 10, 21] ✅ numeric1, 2, 10, 21] ✅ numeric
 
// Sort objects by property
const users = [
  { name: 'Charlie', age: 30 },
  { name: 'Alice', age: 25 },
  { name: 'Bob', age: 35 },
];
const byAge = [...users].sort((a, b) => a.age - b.age); // copy first!
const byName = [...users].sort((a, b) => a.name.localeCompare(b.name));
 
// Spread operator: shallow copy and merge
const original = [1, 2, 3];
const copy = [...original];         // shallow copy
const merged = [...original, 4, 5]; // extend
const combined = [...[1,2], ...[3,4], ...[5]]; // [1,2,3,4,5]1,2,3,4,5]
 
// Destructuring: unpack array values into variables
const [first, second, ...rest] = [10, 20, 30, 40, 50];
console.log(first);  // 10
console.log(second); // 20
console.log(rest);   // [30, 40, 50]30, 40, 50]
 
// Skip elements with empty slots
const [,, third] = ['a', 'b', 'c'];
console.log(third); // 'c'
 
// Swap variables without a temp
let x = 1, y = 2;
[x, y] = [y, x];
console.log(x, y); // 2, 11

Pro Tips — Senior Dev Insights

1

Array.from({ length: n }, (_, i) => ...) is the cleanest way to generate arrays — use it to create ranges, matrices, and mock data.

2

When you need to both filter and transform, flatMap is often cleaner than filter(...).map(...) for cases where map might return empty results.

3

In React and state management, never mutate arrays directly — always return new arrays: setState([...state, newItem]) not state.push(newItem).

Common Developer Pitfalls

!
Calling sort() without a comparator on numbers — [10, 2, 1].sort() returns [1, 10, 2] because it sorts lexicographically (as strings).
!
Mutating arrays you didn't intend to — methods like sort, splice, reverse, push modify the original. Use [...arr].sort() to sort a copy.
!
Confusing splice and slicesplice mutates and removes elements; slice returns a portion without mutating.
!
Using indexOf to find an object in an array — it compares by reference, so the same-looking object won't match unless it's the exact same reference. Use find() with a condition.

Interview Mastery

slice(start, end) returns a copy of a portion of the array without modifying the original. splice(index, deleteCount, ...newItems) modifies the original array by removing and/or inserting elements, and returns the removed elements. Memory trick: 'splice' mutates (both have five letters and are mutating), 'slice' is like slicing off a piece without damaging the whole. In practice, prefer slice and spread over splice for immutable patterns.

Use sort() with a comparator: arr.sort((a, b) => a.property - b.property) for numbers, or a.property.localeCompare(b.property) for strings. Always sort a copy to avoid mutating the original: [...arr].sort(...). For multiple sort keys: sort by first key, return 0 to fall through to the next comparator: (a, b) => a.age - b.age || a.name.localeCompare(b.name).

Destructuring unpacks array values into named variables: const [first, second, ...rest] = array. Useful for: function return values (const [data, error] = fetchData()), swapping variables ([a, b] = [b, a]), ignoring elements (const [,,third] = arr), working with React useState (const [count, setCount] = useState(0)). It's cleaner than indexed access and documents intent — the variable name describes what the value represents.

Hands-on Lab Exercises

1
Build a task manager: implement addTask, removeTask, completeTask, getByPriority functions — use only immutable array operations.
2
Write a sortBy(arr, key, direction) function that sorts an array of objects by any property in ascending or descending order.
3
Implement groupBy(arr, key) using reduce — it should return an object grouping array items by a property value.
4
Flatten a nested array of arbitrary depth and deduplicate the result using flat(Infinity) and a Set.

Real-World Practice Scenarios

Shopping cart: Immutably add, remove, and update quantities in a cart array. Calculate total, item count, and check if a product is in the cart.
Leaderboard: Sort players by score descending, then by name alphabetically as a tiebreaker. Show top 10 with their rank.
Search and filter: Filter a product catalogue by multiple criteria simultaneously (category, price range, availability). Chain array methods.
Data transformation: Convert an array of CSV-like strings into an array of objects — use map and destructuring.

Deepen Your Knowledge