Skip to content

hakeemsalman/javascript-array-cheatsheet

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Arrays

Click ★ if you like the project. Your contributions are heartily ♡ welcome.


Other cheatsheet or notes links


SHORT NOTES is provided in this LINK


Declaration

  • It is a Special data structures which is used to store ordered collections.

  • There are two syntaxes ➀:

  • Array elements are numbered, starting with zero.

  • We can get an element by its number in square brackets ➁:

  • We can replace an element and also can add new one to the array ➂.

  • An array can store elements of any type ➃

    • // ---------------------------------------------> 1
      let arr = new Array();
      let arr = [];
      
      // ---------------------------------------------> 2
      let fruits = ["Apple", "Orange", "Plum"];
      alert(fruits[0]); // Apple
      alert(fruits[1]); // Orange
      
      // ---------------------------------------------> 3
      fruits[1] = "Pear";
      
      // ---------------------------------------------> 4
      let arr = [
        "Apple", // string
        {
          // object
          name: "John",
        },
        true, // boolean
        function () {
          // function
          alert("hello");
        },
      ];

Array has two use cases.

  1. Stack
    1. new elements are added or taken always from the “end”.
    2. A stack is usually illustrated as a pack of cards: new cards are added to the top or taken from the top
    3. LIFO (Last-In-First-Out) principle
    • push adds an element to the end.
    • pop takes an element from the end.
  2. Queue
    1. means an ordered collection of elements which supports two operations:
      1. In practice we need it very often. For example, a queue of messages that need to be shown on-screen.
      2. FIFO (First-In-First-Out).
  • push appends an element to the end.
  • shift get an element from the beginning, advancing the queue, so that the 2nd element becomes the 1st.

    Arrays in JavaScript can work both as a queue and as a stack. They allow you to add/remove elements, both to/from the beginning or the end. In CS called as deque.

Methods pop/push, shift/unshift

  • pop: Remove/Extracts the last element of the array and returns it:
  • push: Append the element to the end of the array:
  • shift: Remove/Extracts the first element of the array and returns it
  • unshift: Add the element to the beginning of the array
let fruits = ["Apple", "Orange", "Pear"];

alert(fruits.pop()); // remove "Pear"                    alert -----> "Pear"
alert(fruits.push("Pear")); // append element to the end        alert -----> "3"
alert(fruits.shift()); // remove "Apple"                   alert -----> "Apple"
alert(fruits.unshift("Mango")); // append element to the beginning  alert -----> "3"

alert(fruits); // Mango,Orange,Pear

How Arrays works internally

  • An array is a special kind of object.
  • The square brackets used to access a property arr[0] actually come from the object syntax.
  • That’s essentially the same as obj[key], where arr is the object, while numbers are used as keys.

But what makes arrays really special is their internal representation. The engine tries to store its elements in the contiguous memory area, one after another, just as depicted on the illustrations in this chapter, and there are other optimizations as well, to make arrays work really fast.

But they all break if we quit working with an array as with an “ordered collection” and start working with it as if it were a regular object.

Please think of arrays as special structures to work with the ordered data. They provide special methods for that. Arrays are carefully tuned inside JavaScript engines to work with contiguous ordered data, please use them this way. If you need arbitrary keys, chances are high that you actually require a regular object {}.

Performance

  • Methods push/pop run fast
  • While shift/unshift are slow.

The shift operation must do 3 things:

  • Remove the element with the index 0.
  • Move all elements to the left, renumber them from the index 1 to 0, from 2 to 1 and so on.
  • Update the length property.

The more elements in the array, the more time to move them, more in-memory operations.

The push/pop operation have only one thing to do:

  • To extract an element from the end
  • the pop method cleans the index and shortens length.

The pop method does not need to move anything, because other elements keep their indexes. That’s why it’s blazingly fast.

Loops

There are three ways to iterate the array:

  • for (Old traditional way)
  • for..of
  • for..in (object is bad idea)
let arr = ["Apple", "Orange", "Pear"];

// Traditional way
for (let i = 0; i < arr.length; i++) {
  alert(arr[i]);
}

// iterates over array elements
for (let fruit of fruits) {
  alert(fruit);
}

// NOT RECOMMANDATION
for (let key in arr) {
  alert(arr[key]); // Apple, Orange, Pear
}

But that’s actually a bad idea. There are potential problems with it:

  1. The loop for..in iterates over all properties, not only the numeric ones.
    1. There are so-called “array-like” objects in the browser and in other environments, that look like arrays. That is, they have length and indexes properties, but they may also have other non-numeric properties and methods, which we usually don’t need. The for..in loop will list them though. So if we need to work with array-like objects, then these “extra” properties can become a problem.
  2. The for..in loop is optimized for generic objects, not arrays, and thus is 10-100 times slower. Of course, it’s still very fast. The speedup may only matter in bottlenecks. But still we should be aware of the difference.

Generally, we shouldn’t use for..in for arrays.

A word about length

  • The length property automatically updates when we modify the array.
  • It is the greatest numeric index plus one.
  • let fruits = [];
    fruits[123] = "Apple";
    
    alert(fruits.length); // 124

lenght is writable

  • If we increase it manually, nothing interesting happens.

  • But if we decrease it, the array is truncated.

  • The process is irreversible:

    • let arr = [1, 2, 3, 4, 5];
      
      arr.length = 2; // truncate to 2 elements
      alert(arr); // [1, 2]
      
      arr.length = 5; // return length back
      alert(arr[3]); // undefined: the values do not return

So, the simplest way to clear the array is: arr.length = 0;.

new Array()

  • There is one more syntax to create an array:
    • let arr = new Array("Apple", "Pear", "etc");
  • If new Array is called with a single argument which is a number,
  • then it creates an array without items, but with the given length.
  • To avoid such suprises, we usually use square brackets.
let arr = new Array(2); // will it create an array of [2] ?

alert(arr[0]); // undefined! no elements.

alert(arr.length); // length 2

Multidimensional arrays

  • Arrays can have items that are also arrays.
  • We can use it for multidimensional arrays:
let matrix = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9],
];

alert(matrix[0][1]); // 2, the second value of the first inner array

toString

  • Arrays have their own implementation of toString method that returns a comma-separated list of elements.
let arr = [1, 2, 3];

alert(arr); // 1,2,3
alert(String(arr) === "1,2,3"); // true

Don’t compare arrays with ==

  • Let’s recall the rules:

    • Two objects are equal == only if they’re references to the same object.
    • If one of the arguments of == is an object, and the other one is a primitive, then the object gets converted to primitive, as explained in the chapter Object to primitive conversion.
    • …With an exception of null and undefined that equal == each other and nothing else.
  • To compare arrays, don’t use the == operator (as well as >, < and others), as they have no special treatment for arrays. They handle them as any objects, and it’s not what we usually want.

Instead you can use for..of loop to compare arrays item-by-item.

Modifying Methods(Adding/Removing Elements)

splice

  • Modifies the original array by adding, removing, or replacing elements at a specified index.
  • Takes three arguments: starting index, number of elements to remove, and optional elements to add.
  • Returns an array of removed elements.
  • Negative indexes allowed (Negative means from the end of the array)

Parameter: splice(start, deleteCount, <item1, item2, /* …, */ itemN>)
in-place: YES

let arr = [1, 2, 3, 4, 5];
let removed = arr.splice(2, 2, 6, 7); // Removes 2 elements from starting index 2, adds 6 and 7
// Result: arr = [1, 2, 6, 7, 5],
// returned array: removed = [3, 4]
alert(arr.splice(0)); // [1, 2, 3, 4, 5] removed all elements
alert(arr); // [] empty array

arr = [1, 2, 5];
// from index -1 (one step from the end)
// delete 0 elements,
// then insert 3 and 4
arr.splice(-1, 0, 3, 4);

alert(arr); // 1,2,3,4,5

push

pop

unshift

shift

fill

copyWithin

Extracting Methods (Non-Modifying)

slice

  • Returns a shallow copy of a portion of the array, based on the start and end indices provided.
  • Does not modify the original array.
  • Does NOT include end indexes value.
  • Both start and end can be negative (it means from the end of the array)
  • It’s similar to a string method str.slice, but instead of substrings, it makes subarrays.

Parameter: slice(<start>, <end>)
in-place: NO

let arr = [1, 2, 3, 4, 5];
let result = arr.slice(1, 3); // Extracts elements from index 1 to 3 (not including 3)
// Result: result = [2, 3], arr = [1, 2, 3, 4, 5]

let arrCopy = arr.slice(); // copy of arr, call without arguments

We can also call it without arguments: arr.slice() creates a copy of arr. That’s often used to obtain a copy for further transformations that should not affect the original array.

concat

  • Combines two or more arrays and returns a new array.
  • Does not modify the original arrays.

Parameter: concat(value1, <value2, /* …, */ valueN>)
in-place: NO

let arr1 = [1, 2];
let arr2 = [3, 4];
let result = arr1.concat(arr2); // Combines arr1 and arr2
// Result: result = [1, 2, 3, 4]

toSpliced

Iteration Methods (Looping through arrays)

forEach

  • Executes a provided function once for each array element.
  • Does not return a new array or modify the original array.

Parameter: forEach(callbackFn, <thisArg>)
  ♦ callbackFn(element, <index>, <array>)
in-place: NO

let arr = [1, 2, 3];
arr.forEach((num, index) => console.log(`Index ${index}: ${num}`));
// Logs each element and
// index:
//    "Index 0: 1"
//    "Index 1: 2"
//    ...
//    ...etc.

The result of the function (if it returns any) is thrown away and ignored.

entries

keys

values

Searching Methods

indexOf

  • It Returns the first index at which a given element can be found, or -1 if not found.
  • It uses the strict equality === for comparison.
  • It does not handle NaN correctly. (see includes)
  • Parameter: indexOf(searchElement, <fromIndex>)
    in-place: NO
let arr = [1, 2, 3, 2];
let first = arr.indexOf(2); // Result: 1

const arr = [NaN];
alert(arr.indexOf(NaN)); // -1 (wrong, should be 0)

lastIndexOf

  • lastIndexOf(value): Returns the last index at which an element appears, or -1 if not found.

Parameter: lastIndexOf(searchElement, <fromIndex>)
in-place: NO

let arr = [1, 2, 3, 2];
let last = arr.lastIndexOf(2); // Result: 3

includes

  • Returns true if the array contains a specified element; otherwise, returns false.
  • If we want to check if item exists in the array and don’t need the index, then arr.includes is preferred.
  • Negative index counts back from the end of the array.
  • The includes method handles NaN correctly, a vice-versa of indexOf.

Parameter: includes(searchElement, <fromIndex>)
in-place: NO

let arr = [1, 2, 3];
alert(arr.includes(2)); // Result: true
alert(arr.includes(2, 1)); // Result: true
alert(arr.includes(2, -1)); // Result: false
alert(arr.includes("2")); // Result: false

const arr = [NaN];
alert(arr.indexOf(NaN)); // -1 (wrong, should be 0)
alert(arr.includes(NaN)); // true (correct)

find

  • It Returns the first element that satisfies the callback function’s test.
  • If it returns true, the search is stopped, the item is returned. If nothing is found, undefined is returned.
  • It looks for a single (first) element that makes the function return true. For many use filters

Parameter: find(callbackFn, <thisArg>)
  ♦ callbackFn(element, <index>, <array>)
in-place: NO

let result = arr.find(function (item, index, array) {
  // if true is returned, item is returned and iteration is stopped
  // for falsy scenario returns undefined
});

let users = [
  { id: 1, name: "John" },
  { id: 2, name: "Pete" },
  { id: 3, name: "Mary" },
];

let user = users.find((item) => item.id == 1);
let userUndefined = users.find((item) => item.id == 4);

alert(user.name); // John
alert(userUndefined?.name); // undefined

🙌 You can practice problems from this LINK 😎


findLast

findIndex

  • It Returns the index of the first element that satisfies the test, or -1 if not found.

Parameter: findIndex(callbackFn, <thisArg>)
  ♦ callbackFn(element, <index>, <array>)
in-place: NO

let users = [
  { id: 1, name: "John" },
  { id: 2, name: "Pete" },
  { id: 3, name: "Mary" },
  { id: 4, name: "John" },
];

// Find the index of the first John
alert(users.findIndex((user) => user.name == "John")); // 0

You can practice problems from this LINK

findLastIndex

  • findLastIndex(callback): Returns the last index where the condition is true.

Parameter: findLastIndex(callbackFn, <thisArg>)
  ♦ callbackFn(element, <index>, <array>)
in-place: NO

let users = [
  { id: 1, name: "John" },
  { id: 2, name: "Pete" },
  { id: 3, name: "Mary" },
  { id: 4, name: "John" },
];

// Find the index of the last John
alert(users.findLastIndex((user) => user.name == "John")); // 3

filter

  • Similar to find but it returns as a array of pass elements instead of single element.
  • Creates a Shallow copy (new array) with all elements that pass the test implemented by the provided function.
  • Does not modify the original array.
  • If no elements pass the test, an empty array is returned.
  • It should return a truthy value to keep the element in the resulting array, and a falsy value otherwise.

Parameter: filter(callbackFn, <thisArg>)
  ♦ callbackFn(element, <index>, <array>)
in-place: NO

// SYNTAX
let results = arr.filter(function (item, index, array) {
  // if true item is pushed to results and the iteration continues
  // returns empty array if nothing found
});

let arr = [1, 2, 3, 4];
let result = arr.filter((num) => num % 2 === 0); // Filters even numbers
// Result: result = [2, 4]

at

Transforming Methods (Modifying elements)

map

  • Creates a new array by applying a provided function to each element in the array.
  • Does not modify the original array.

Parameter: map(callbackFn, <thisArg>)
  ♦ callbackFn(element, <index>, <array>)
in-place: NO

let arr = [1, 2, 3];
let result = arr.map((num) => num * 2); // Multiplies each element by 2
// Result: result = [2, 4, 6]

flat

flatMap

sort

  • Sorts the elements of an array in place (modifies the original array).
  • Takes an optional comparison function fn to define custom sorting logic.
  • The items are sorted as strings by default. ①
    • All elements are converted to strings for comparisons. For strings, lexicographic ordering is applied and indeed "2" > "15".
  • For many alphabets, it’s better to use str.localeCompare method to correctly sort letters, such as Ö. ②
  • To sort the elements in an array without mutating the original array, use toSorted().

Parameter: sort(<compareFn>)
  ♦ callbackFn(a, b)
in-place: YES

// items sorted as string -----------------------------> ( 1 )
let arr = [1, 2, 15];
// the method reorders the content of arr
arr.sort();
alert(arr); // 1, 15, 2
//"2".codePointAt() is 50 where as "15".codePointAt() is 49. So 50 is greater than 49.

// custom logic func in sorting
function compareNumeric(a, b) {
  if (a > b) return 1;
  if (a == b) return 0;
  if (a < b) return -1;
}
let arr = [1, 2, 15, 8, 21, 10, 3, 4];
arr.sort(compareNumeric);
alert(arr); // 1, 2, 15

let arr = [3, 1, 4, 2];
arr.sort((a, b) => a - b); // Sorts in ascending order
arr.sort((a, b) => b - a); // Sorts in descending order
alert(arr); // Result: arr = [1, 2, 3, 4]

// Use localeCompare for alphabets: ---------------------------> ( 2 )
let countries = ["Österreich", "Andorra", "Vietnam"];
alert(countries.sort((a, b) => (a > b ? 1 : -1))); // Andorra, Vietnam, Österreich (WRONG)
alert(countries.sort((a, b) => a.localeCompare(b))); // Andorra,Österreich,Vietnam (CORRECT!)

🙌 You can practice problems from this LINK 😎


reverse

  • Reverses the order of elements in place.
  • Sparse arrays remain sparse after calling reverse(). Empty slots are copied over to their respective new indices as empty slots.
  • To reverse the elements in an array without mutating the original array, use toReversed().

Parameter: reverse()
in-place: YES

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

join

  • It Joins all elements of an array into a single string, separated by a specified delimiter.
  • It returns a string of all elements of arrays. Parameter: join(<separator>)
    in-place: NO
let arr = ["Bilbo", "Gandalf", "Nazgul"];
let str1 = arr.join(";"); // glue the array into a string using ;
let str2 = arr.join(", ");
let str3 = arr.join("");
alert(str1); // Bilbo;Gandalf;Nazgul
alert(str2); // Bilbo, Gandalf, Nazgul  (it's a string not an array)
alert(str3); // BilboGandalfNazgul

Reducing Methods

reduce

  • Applies a function against an accumulator and each element (left-to-right) to reduce the array to a single value.
  • As the function is applied, the result of the previous function call is passed to the next one as the first argument.
  • We also can omit the initial value. reduce takes the first element of the array as the initial value. And continue with 2nd element.
  • If the array is empty, then reduce call without initial value gives an error
  • If initial value is given, then reduce would return initial value with empty array.
  • So it’s advised to always specify the initial value.

Parameter: reduce(callbackFn, <initialValue>)   ♦ callbackFn(accumulator, currentValue, currentIndex, array).

  • arguments
         ♦accumulator: is the result of the previous function call, equals initial the first time (if initial is provided).
         ♦item: is the current array item.
         ♦index: is its position.
         ♦array: is the array

in-place: NO

  • Exceptions:
  • TypeError: Thrown if the array contains NO elements and initialValue is not provided
// SYNTAX
let value = arr.reduce(
  function (accumulator, item, index, array) {
    // ...
  },
  [initial]
);

let arr = [1, 2, 3, 4, 5];
let sum = arr.reduce((sum, num) => sum + num, 0); // Sum of all elements
// Result: sum = 15
sum
0
current
1
sum
0+1
current
2
sum
0+1+2
current
3
sum
0+1+2+3
current
4
sum
0+1+2+3+4
current
5
1 2 3 4 5 0+1+2+3+4+5 = 15
sum current result
the first call 0 1 1
the second call 1 2 3
the third call 3 3 6
the fourth call 6 4 10
the fifth call 10 5 15

For more information, please follow this LINK

reduceRight

  • It Similar to reduce, but works right-to-left.
  • For more in depth information, please follow this LINK

Parameter: reduceRight(callbackFn, <initialValue>)
in-place: NO

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

// Error: Reduce of empty array with no initial value
// if the initial value existed, reduce would return it for the empty arr.
arr.reduceRight(
  (sum, current) => console.log(sum + current, "and ", current),
  0
); // 5, 4, 3, 2, 1

Validation Methods (Checking Conditions)

every

some

Type Checking Methods

Array.isArray

  • Determines if a value is an array.
  • Returns true if the value is an array, otherwise false.
  • So typeof does not help to distinguish a plain object from an array. ①
// typeof -------------------------------------------------------> ( 1 )
alert(typeof {}); // object
alert(typeof []); // object (same)

alert(Array.isArray({})); // false
alert(Array.isArray([])); // true

Utility Methods

with

toString

  • Arrays have their own implementation of toString method that returns a comma-separated list of elements.
let arr = [1, 2, 3];

alert(arr); // 1,2,3
alert(String(arr) === "1,2,3"); // true

thisArg in Array Methods

  • Many array methods, like map(), forEach(), and filter(), support an optional thisArg parameter.
  • thisArg lets you specify the value of this inside the callback function, allowing custom contexts to be passed.
let arr = [1, 2, 3];
let multiplier = {
  factor: 2,
};

let result = arr.map(function (num) {
  return num * this.factor;
}, multiplier); // Sets `this` to `multiplier` object
// Result: result = [2, 4, 6]