Introduction
Arrays are highly useful for storing ordered collections of data, but not until they are blended together with array properties and methods.
In this chapter we shall get an overview of the most fascinating methods available to all array instances and the all-time favourite length
property.
Joining multiple arrays together
To join — or better to say, concatenate — two or more arrays together into a single array we could use the concat()
method.
Call it on a given array whose elements you want to appear first in the final array and then pass the rest of arrays one-by-one as arguments.
Something as follows:
arr1.concat(arr2, arr3, ...., arrN)
The order in which the arrays appear in the expression above is exactly the same order in which there elements are laid out in the final away.
concat()
method does not modify the original array (or any other array). It returns a new array composed by joining all the given arrays together.The method concat()
can be useful often times. Let's say we have three different lists of numbers which represent the marks of three different students in recent exams out of 100:
var a = [75, 54, 70],
var b = [94, 60, 78];
var c = [67, 80, 81];
Now we would like to display all these numbers in sorted.
For this we'll need to first join all the three lists together and then perform the sorting on the array obtained in the end. In the code below, we accomplish this idea and finally log the resulting array:
var a = [75, 54, 70];
var b = [94, 60, 78];
var c = [67, 80, 81];
var allNums = a.concat(b, c);
console.log(allNums.sort(function(a, b) { return a - b; }));
Filling an array
If we wish to set each element of an array to the same value, we could iterate over it and assign each index that very value. An example follows:
To fill an array with a single value in a single command, we could use the fill()
method.
Just pass it the respective value and the given array would be filled with that value at each index.
arr.fill(value[, start[, end]])
By default, start
and end
default to 0
and arr.length
, respectively. That is, every element would be replaced by value
. Explicitly providing a value to these parameters would fill the array only upto the specified length.
The return value of fill()
is the filled array. Note that fill()
mutates the original array.
Consider the snippet below:
[1, 2, 3, 4].fill(0)
[1, true, 'Hello'].fill(100)
If the array is empty, there won't be any consequene of calling fill()
on it, as can be seen below:
[].fill(0)
[].fill(0, 0, 3)
In the last statement here, you might expect the method to fill the first three indexes of the array with 0
but this does not happen. The reason is because the array is empty, i.e. it's length
is equal to 0
.
fill()
method doesn't process empty arrays.One trick we could use with fill()
is to initialize an array to a given length using Array(n)
and then fill it with a given value. This could be extremely handy when we have to work with a preinitialized array, where otherwise creating the array manually using literals would be quite a strenous activity.
Let's quickly consider an example. Suppose we have to create an array holding 100 values each initialized to 0
. As you would agree, doing so manually would be quite repetitive and monotonous.
A better way is to create an array to the desired length using Array(100)
and then fill it with the value 0
.
Shown below is an illustration:
var arr = Array(100).fill(0);
console.log(arr[0]);
console.log(arr[50]);
console.log(arr[99]);
0
0
Voila! All of the three elements inspected are equal to 0
.
Slicing an array
To extract out a given subarray from an array, we could use the slice()
method.
slice()
method takes a starting (inclusive) and ending index (exclusive) and returns a copy of the array in that range.Shown below is its syntax:
arr.slice([start [, end]])
start
specifies the index where to start the slicing. This is inclusive, and defaults to 0
. end
specifies the index where to end the slicing. This is exclusive, and defaults to arr.length
.
slice()
method, with exactly the same syntax of arguments, for strings back in the JavaScript String Methods chapter.Let's consider a couple of examples:
var nums = [1, 2, 3, 4, 5];
console.log(nums.slice(0, 0)); // []
console.log(nums.slice(0, 1)); // [1]
console.log(nums.slice(1, 4)); // [2, 3, 4]
In the first statement, calling slice(0, 0)
returns an empty array because the slicing begins at 0
and ends before 0
(at -1
, which is clearly impossible!).
In the second statement, calling slice(0, 1)
returns the array [1]
by beginning slicing at index 0
and ending it just before 1
(i.e 0
).
In the last statement, calling slice(1, 4)
returns the array [2, 3, 4]
because slicing this time begins at index 1
and ends just before index 4
. This accounts for the indexes 1
, 2
and 3
(4
being exclusive).
Figure out the return value of nums.slice()
for the nums
array above.
Keep in mind the default values of both the start
and end
arguments.
undefined
[]
[1, 2, 3, 4]
Adding/removing elements at the end
As we saw in the previous chapter, to add an element, or a set of elements, at the end of an array, we could use the push()
method.
push()
method adds an element to the end of an array.The syntax is pretty straightforward:
arr.push(item1, item2, ..., itemN)
We could pass just one element item1
to be added to arr
; or pass a set of items item1
, item2
, all the way to itemN
, to be added to the array.
Note that push()
changes the length of the calling array.
Let's use push()
to add a couple of elements to an array:
var nums = [1, 2];
nums.push(3);
console.log(nums);
nums.push(4);
console.log(nums);
In a similar way that we could add an element to the end of an array, we could remove it from there as well. For this, we have the pop()
method.
pop()
method removes an element from the end of an array.Since pop()
merely removes the last element from an array, it doesn't require any arguments:
arr.pop()
pop()
returns the element removed. This is useful because, often times, we have to use the value in the program before losing it completely.
Following from the last code, let's remove the last two elements using pop()
:
var nums = [1, 2];
nums.push(3);
nums.push(4);
console.log(nums);
console.log('Removing', nums.pop());
console.log('Removing', nums.pop());
console.log(nums);
Removing 4
Removing 3
[1, 2]
Simple, wasn't it?
Adding/removing elements at the start
As we saw just right now, push()
and pop()
serve to add and remove stuff from the end of a given array. In JavaScript, and most programming languages that support dynamic arrays, we could do so at the start of the array as well.
The methods used in this case are unshift()
and shift()
.
unshift()
method adds an element to the start of an array.Parameter-wise, it's same as push()
:
arr.unshift(item1, item2, ..., itemN)
The given arguments are added to the start of arr
. Simple.
Let's consider a quick example:
var nums = [1, 2];
nums.unshift(3);
console.log(nums);
nums.unshift(4);
console.log(nums);
To remove an element from the start of an array, we use the shift()
method.
shift()
method removes an element from the start of an array.It's syntactically the same as pop()
:
arr.shift()
The return value of shift()
is the element removed.
Let's consider a quick example following from the last code snippet above:
var nums = [1, 2];
nums.unshift(3);
nums.unshift(4);
console.log(nums);
console.log('Removing', nums.shift());
console.log('Removing', nums.shift());
console.log(nums);
Removing 4
Removing 3
[1, 2]
Adding/removing elements at arbitrary indices
To add and/or remove stuff from an array starting at an arbitrary index, instead of the beginning or end of the array, we have the splice()
method at our dispense.
splice()
is meant to add/remove elements from an array, in-place, starting from a given index.Note that splice()
mutates the original array.
Here's its syntax:
arr.splice([index[, deleteCount[, item1[, item2[, ...[, itemN]]]]]])
index
is the index where to begin the addition and/or removal of stuff. It defaults to0
.deleteCount
specifies the number of items to delete starting from the positionindex
. Ifindex
is not specified, i.e.splice()
is called without any arguments,deleteCount
is0
. Otherwise, it is set toarr.length - index
i.e. removes all elements upto the end of the array, starting fromindex
.item1
,item2
, all the wayitemN
, specify the elements to add atindex
. If omitted, nothing is added.
The return value of splice()
is an array holding the deleted items of the main array. If nothing is deleted, i.e. deleteCount
is 0
, an empty array is returned.
Time for some examples...
Let's say we have the following array and want to remove the second element from it:
var arr = [1, 50, -6, -20, 22];
How would we do so?
Well, the second element is at index 1, and this is the position where the removal should begin; hence the first index
arg to splice()
becomes 1
.
Moving on, since only one element is to be deleted, deleteCount
would also be 1
. And finally, because nothing ought to be added, no args follow along.
Below, we perform the removal, and log both arr
and the array holding the removed item:
var arr = [1, 50, -6, -20, 22];
var deletedArr = arr.splice(1, 1);
console.log(arr);
console.log(deletedArr);
[50]
See how the deleted element 50
is accessible as an element of deletedArr
.
In a real-world application, you might want to work with the set of removed items and that's where the return value of splice()
could help.
Let's see a couple more examples.
Say we have to delete the second last element from an array arr
. What would the set of args to splice()
be?
Simple — arr.splice(-2, 1)
.
An illustration follows:
var arr = [1, 50, -6, -20, 22];
var deletedArr = arr.splice(-2, 1);
console.log(arr);
console.log(deletedArr);
[-20]
What if we want to remove nothing from an array, but rather add two elements at the second position? Hmm..
We'll call arr.splice(1, 0, ele1, ele2)
.
An illustration follows:
var arr = [1, 50, -6, -20, 22];
var deletedArr = arr.splice(1, 0, 'Hello', 'World!');
console.log(arr);
console.log(deletedArr);
[]
Since nothing is removed in the array arr
above, splice()
returns an empty array.
Calling splice()
without any arguments merely returns an empty array:
var arr = [1, 2, 3];
console.log(arr.splice());
Reversing an array
Want to switch the order of elements of an array? Simply use the reverse()
method.
reverse()
method reverses the order of elements of a given array, in place.It's simple in nature:
arr.reverse()
Note that as with sort()
, reverse()
mutates the original array and returns it back.
Shown below is an example:
var subs = ["Chemistry", "Physics", "Math"];
console.log(subs.reverse());
console.log(subs);
["Math", "Physics", "Chemistry"]
In the first log statement, the reverse()
method returns back the reversed version of subs
and this is logged in the console. The second log statement outputs the same array as before. This confirms that the original array subs
was mutated by subs.reverse()
.
reverse()
method on that copy.Finding index of an element
Do you recall the indexOf()
and lastIndexOf()
methods all the way back from the JavaScript String Methods chapter?
Both these methods are available on array instances as well and serve a similar purpose — to return the index of a given element.
Let's see each one...
indexOf()
method finds a given element in an array and returns its index; or otherwise the value -1
.The method is comprised of two parameters:
arr.indexOf(value[, index])
value
is the value to look for in arr
while index
is the index where to start the searching. This defaults to 0
i.e the beginning of the array.
The indexOf()
method finds a match for value
in arr
using a strict-equality comparison (the one employed by the ===
operator).
Shown below are a couple of examples:
[1, 2, 3, 4].indexOf(1)
[1, 2, 3, 4].indexOf(4)
[1, 2, 3, 4].indexOf(5)
[1, 2, 3, 4].indexOf("1")
[1, true, true, false].indexOf(true)
indexOf()
without an argument would make value
equal to undefined
.Similar to indexOf()
, which finds the first match for a given value, the lastIndexOf()
method finds the index of the last match of a given value.
lastIndexOf()
method finds a given element in an array, starting from the end, and returns its index; or otherwise the value -1
.Syntactically, it's identical to indexOf()
:
arr.lastIndexOf(value[, index])
Consider the snippet below:
[1, 2, 3, 4].lastIndexOf(1)
[1, 2, 3, 4].lastIndexOf(4)
[1, 2, 3, 4].lastIndexOf(5)
[1, 2, 3, 4].lastIndexOf("1")
[1, true, true, false].lastIndexOf(true)
[1, 1, 0, 1].lastIndexOf(1)
Existential and universal quantification
In elementary logic, specifically in predicate logic, there is this idea of some item in a given set of items meeting a certain condition. We call this existential quantification.
A similar idea is that of universal quantification, where every single element meets the given condition.
These ideas of checking whether in a set of items, at least one or all elements meet a certain condition are present in JavaScript arrays as well. They are exposed by the some()
and every()
methods, respectively.
some()
takes a function and returns true
if the function evaluates to true
for at least one element in the calling array.Time to see its syntax:
arr.some(callbackFn)
callbackFn
is a function that is run for every element of arr
until it evaluates down to true
. Here's the syntax of the callback function:
callbackFn(element, index, array, thisValue)
element
is the element ofarr
currently under inspection.index
is the index ofelement
.array
holds a reference toarr
.thisValue
is the value to be used in place ofthis
inside the callback function.
Let's consider a quick example.
Say we want to confirm whether in a list of numbers, there is at least on square number. We could solve this by laying out the callback function as follows:
function isSquare(element) {
return Number.isInteger(element ** 0.5);
}
If any one element in the list of numbers is a square isSquare()
would return true
for it and hence cause some()
to return true
as well.
Shown below are a couple of examples:
function isSquare(element) {
return Number.isInteger(element ** 0.5);
}
var nums = [1, 2, 3];
console.log(`Square in ${nums}`, nums.some(isSquare));
nums = [2, 3, 4];
console.log(`Square in ${nums}`, nums.some(isSquare));
nums = [2, 3, 5, 7];
console.log(`Square in ${nums}`, nums.some(isSquare));
nums = [2, 3, 5, 7, 49, 100];
console.log(`Square in ${nums}`, nums.some(isSquare));
Square in [2, 3, 4]: true
Square in [2, 3, 5, 7]: false
Square in [2, 3, 5, 7, 49, 100]: true
Following from the fact that for some()
to return true
, there has to be at least one element in the array for which the callback function returns true
, when the array is empty i.e. has not elements, some()
returns false
.
Consider the following code:
function isSquare(element) {
return Number.isInteger(element ** 0.5);
}
console.log([].some(isSquare));
In the same way, to check whether every single element in an array meets a given condition, we could use the every()
method.
every()
takes a function and returns true
if the function evaluates to true for every single element in the calling array, or otherwise false
.It's syntactically identical to some()
:
arr.every(callbackFn)
Check out the syntax for callbackFn
above.
The main difference is that the given callback function is run for every element in the given array and if, for any one, it returns false
, every()
returns false
as well. It's only when the function returns true
for every element in the array that every()
returns true
.
Let's say we want to confirm whether a student passed in all exams. The passing marks are above 50
. If the student's marks were modeled by an array marks
, we could use every()
to solve this task.
Shown below is an illustration:
function above50(marks) {
return marks >= 50;
}
var marksList = [35, 80, 54, 90, 60];
console.log(marksList.every(above50));
marksList = [78, 86, 70, 95, 71];
console.log(marksList.every(above50));
true
Following from the fact that for every()
to return false
, there has to be at least one element in the array for which the callback function returns false
, when the array is empty i.e. has not elements, every()
returns true
.
Consider the following code:
function above50(marks) {
return marks >= 50;
}
console.log([].every(above50));
Filtering elements
To obtain only those elements from an array that meet a given condition, we use the filter()
method.
filter()
takes in a callback function and returns an array containing all the elements in the calling array for which the callback function returns true
.
If you think on for a second, the word 'filter' is quite a sensible name for this method. It says to filter out elements from an array based on a given condition.
Pretty clever naming!
Say we want to extract out all positive values from an array of numbers. For this we'll set up the callback function as follows:
function positiveNumber(num) {
return num > 0;
}
This would return true
only for those numbers that are greater than 0
. Let's use this function along with filter()
on a couple of arrays and see the outcome in each case:
function positiveNumber(num) {
return num > 0;
}
var nums = [10, 5, -4, -1, 50, 34, -27];
console.log(nums.filter(positiveNumber));
nums = [0, 15, 0, -6, -1, -4, -0.5, 3.1, 10.5];
console.log(nums.filter(positiveNumber));
[15, 3.1, 10.5]
filter()
method is no doubt worth it!Create an array evens
by filtering out all the even-indexed elements from the following nums
array:
var nums = [1, 10, 5, 33, 198, 0, 5, 8];
Your evens
array shall be equal to [1, 5, 198, 5]
as these elements have even indexes in nums
— 0
, 2
, 4
, and 6
respectively.
Think of the second parameter of the callback function passed to filter()
.
var nums = [1, 10, 5, 33, 198, 0, 5, 8];
var evens = nums.filter(function(e, i) {
return i % 2 === 0;
});
Joining elements together
When working with arrays, it's extremely common to go into a string representation by joining the individual elements together.
If we just want to join the elements with a comma in betweeen we can call the toString()
method,or simply use the array in a string concatenation context.
Both of these are shown below:
[1, 2, 3, 4].toString()
[1, 2, 3, 4] + ''
'The numbers are: ' + [1, 2, 3, 4]
However, if we want some other separator, we could use the join()
method.
It accepts a single string argument which is the separator to put in between the elements:
arr.join([separator])
By default, separator
is set to ','
, which means that arr.join()
is effectively the same as calling arr.toString()
.
The return value of the join()
method is a string containing all elements of arr
separated by separator
.
A common separator used out there is a single space — ' '
.
In the code below, we create an array nums
and then output it with each element being separated from the other one using a space:
var nums = [1, 2, 10, 50, 100];
console.log(nums.join(' '));
Mapping an array
It's a common idea to iterate over an array and map each of its elements onto a new element. These mapped elements are put in a new array.
For instance, suppose we have a list of positive integers. We could create a list of squares outt= of it by mapping each integer to the square of that integer. Similarly, we could even obtain a list of cubes using this same list of positive integers.
In JavaScript, we could use the map()
method to create a new array based on a given array with a mapping function.
map()
method takes a function and returns a new array comprised of elements returned by the function for each element of the calling array.Let's see its syntax:
arr.map(mappingFn[, thisValue])
Given an element (and other arguments), the mapping function mappingFn
simply returns the new value which ought to be put in the new array. Its syntax is similar to that of the callback function passed to some()
, every()
, filter()
etc.
mappingFn(element, index, thisValue)
element
is the element ofarr
currently under inspection.index
is the index ofelement
.array
holds a reference toarr
.
The thisValue
argument specifies the value that this
refers to inside the callback function. Almost always, you won't find yourself in need of this.
Let's consider a couple of examples...
Below we have an array ints
which is used to create two more arrays squares
and cubes
:
function toSquare(int) { return int ** 2 };
function toCube(int) { return int ** 3 };
var ints = [0, 1, 2, 3, 4, 5];
var squares = ints.map(toSquare);
console.log(squares);
var cubes = ints.map(toCube);
console.log(cubes);
// let's see if ints has been modified
console.log(ints);
[0, 1, 8, 27, 64, 125]
[0, 1, 2, 3, 4, 5]
The last log here confirms the fact that calling map()
on an array does not mutate it.
Going ahead, a common practice you'll see in coding competitions out there is to use this notion of mapping to convert a list of stringified numbers into a list of numbers.
In the code below, we convert a string of space-delimited numbers into an array of numbers using a couple of handy methods, including map()
:
var str = '10 -5 40 1 0 0 3';
var nums = str.split(' ').map(Number);
console.log(nums);
Time to understand what's happening over here...
str.split(' ')
breaks apart str
at each space (' '
) character and returns back an array of the left-over strings, as follows:
str.split(' ')
Next up, map()
goes over this array of strings and runs the Number()
function over each string. Recall that, given an argument, Number()
converts it into a number.
Hence, for each string in the array of string shown above, the return value of Number()
is the equivalent number which is put in the array returned by map()
.
A very elegant way to convert a string of numbers into an array of numbers!
Sorting an array
To sort an array in increasing or decreasing order (alphabetic or numeric depending on the application), we use the sort()
method.
When called without an argument, it sorts an array in increasing, alphabetic order. But when called with an argument, that is a function, sort()
sorts the array based on the return value of that function.
Hence, sort()
could be represented as follows:
arr.sort([comparisonFn])
Note that sort()
rearranges and returns the actual array. In other words, it mutates the original array.
Let's take a look over a handful of examples.
When we have to sort an array of strings, there is no need to provide an arg to sort()
. In the code below we sort an array langs
holding the names of some programming languages:
var langs = ['Python', 'Java', 'JavaScript', 'C', 'Fortran', 'ASP'];
console.log(langs.sort());
console.log(langs);
["ASP", "C", "Fortran", "Java", "JavaScript", "Python"]
The last log statement shows that langs
is sorted itself. This confirms that sort()
indeed mutates the original array.
On the contrary, when we want to sort an array of numbers, sort()
might give unexpected results, as demonstrated below:
[100, 25, 3, 70, 8, 10].sort()
The array expected is [3, 8, 10, 25, 70, 100]
, but what's returned is extremely strange and in contradiction to any sort of natural reasoning. How is 100
less than 3
?
However, if you know what's happening under the hood in the sort()
method, this return value would make perfect sense. We'll cover all these peculiar details about the sort()
method in the next chapter on JavaScript Arrays — Sorting.
For now, let's see the way to properly sort an array of numbers.
To sort an array numerically, we have to explicitly tell JavaScript how to compare any two given elements with one another to determine which one should come first in the sorted array. This goes in the form of a function.
Given two args a
and b
, when the function returns a value less than or equal to 0
, b
is put before a
. On the same lines, when the function returns a value greater than 0
, a
and b
remain in their original position.
Consider the following code where we sort an array of numbers numerically:
var nums = [100, 25, 3, 70, 8, 10];
console.log(nums.sort(function(a, b) { return a - b; }));
There is just a lot to cover just in this single sort()
method. All this is detailed in the following chapter on JavaScript Arrays — Sorting.