JavaScript arrays can be either dense or sparse. An array in JavaScript is a collection of multiple elements, and each element is assigned an index that we use to access it. The index number is a positive integer and starts from 0. As a result, if an array contains ten elements, its index number ranges from 0 to 9. But JavaScript also allows us to increase the array’s length without adding an element. Such an array is called a sparse array. In the tutorial, let us learn more about dense and sparse arrays.
Table of Contents
Dense Arrays
An array is dense if it has values at every index. i. e., it has values at the index starting from 0 until the array.length - 1
. The number of elements in the array is always equal to the array.length
For Example, the books
array in the following example is dense. It has a length of 4 and contains values at every index starting from 0 to 3
1 2 3 4 | const books = ["Ulysses", "Don Quixote", "War and Peace", "Moby Dick"]; console.log(books.length) //4 |
The length property in a dense array correctly returns the number of elements in the array.
Sparse Array
The array is sparse when its length exceeds the number of elements. i.e., at least one of the indexes is empty, or the array has holes.
The following example creates a dense array of books
with a length of 4. We set its length to 5. This will increase the array’s length to 5 but not store any value at the index 4. The books
array will become sparse with no value at index 4.
1 2 3 4 5 6 7 8 9 10 | //Example const books = ["Ulysses", "Don Quixote", "War and Peace", "Moby Dick"]; //Set its length to 5 books.length = 5 //array length is 5 console.log(books.length) //5 |
The forEach
method of the array does not iterate over the non-existent element of the array. That is the reason why it will print only four elements.
1 2 3 4 5 6 7 8 9 10 11 | const books = ["Ulysses", "Don Quixote", "War and Peace", "Moby Dick"]; books.length = 5 //But it Prints only 4 element. books.forEach(element => console.log(element)); //Ulysses //Don Quixote //War and Peace //Moby Dick |
Should you use sparse Array
The only good thing about sparse arrays is that they are memory efficient because they utilize less memory (No memory is used for empty items).
Looking up elements in a sparse array is slower because JavaScript treats them as objects and uses the object property lookup to retrieve values. The dense arrays use regular array lookup, which is faster than the property lookup.
Another important thing about a sparse array is that once it becomes sparse, it will never change back to dense, even if you assign values to all the empty values. So, make sure that you always use the array literal notation to create an array with all the values filled. You can assign undefined if you do not have a value.
Hence, unless you have any compelling reason to use a sparse array, always you dense array.
You can refer to the article Array Optimizations in JavaScript Engines for more information.
Ways to create sparse arrays
It is always a good practice to avoid creating a sparse array. But you may unknowingly create sparse arrays. Hence it is better to know ways to make a sparse array in JavaScript.
Omitting value in Array Literal
If we omit a value in Array Literal, it will result in a sparse array.
The values for indexes 3 and 4 are left out in the following example. This will produce a sparse array of only four items with a length of six.
1 2 3 4 5 6 7 8 9 10 11 12 13 | //Example const books = ["Ulysses", "Don Quixote", "War and Peace", , , "Moby Dick"]; console.log(books.length) //6 //But it Prints only 4 element. books.forEach(element => console.log(element)); //Ulysses //Don Quixote //War and Peace //Moby Dick |
Array Constructor
Invoking Array Constructor with only one numeric argument creates a sparse array.
In the following example, the Array(4) (or new Array(4)) creates a sparse array with length four and no elements.
1 2 3 4 5 6 7 8 | const books = Array(4) console.log(books.length) //4 books.forEach(element => console.log(element)); //no output |
Delete Operator
Deleting an item from the array using the delete operator does not re-arrange it but converts it into a sparse array.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | const nums = Array("1","2","3","4") console.log(nums.length) //4 delete nums[2] //only 3 elements in the array nums.forEach(element => console.log(element)); //1 //2 //4 //But length still shows 4 console.log(nums.length) //4 |
Increase Length Property
We can set the length
property of an array to a value that is higher than the highest index
1 2 3 4 5 6 7 8 9 10 11 12 | const books = ["Ulysses", "Don Quixote" ]; books.length = 4 //But it Prints only 2 element. books.forEach(element => console.log(element)); //Ulysses //Don Quixote //Length returns returns the length as 4 console.log(books.length) // 4 |
Insert a key/value at a certain index
Inserting a value at a non-existing index greater than the length will turn the array into a sparse array.
1 2 3 4 5 6 | const books = ["Ulysses", "Don Quixote" ]; books[10]="Test" //Insert value at random index console.log(books.length) //11 |
Undefined and Sparse Array
JavaScript returns undefined when we try to read the empty holes from a sparse array.
The code below deletes the element at index one from the nums1
array. When we try to access nums1[1]
, we get undefined
. While looping through the array, it will skip index one as there is no element.
1 2 3 4 5 6 7 8 9 10 11 | var nums1 = [0, 1, 2, 3]; delete nums1[1] nums1.forEach(function(item) { console.log(item); // 0,2,3 //Only 3 elements. Index 1 is deleted }); console.log(nums1[1]); //undefined |
The following code sets the value of nums2[1]
to undefined. This does not convert nums2
to the sparse array because index one does have a value, and it is undefined.
1 2 3 4 5 6 7 8 9 10 11 | var nums2 = [0, 1, 2, 3]; nums2[1]=undefined nums2.forEach(function(item) { console.log(item); // 0,undefined,2, 3 //element at index 1 has value undefined }); console.log(nums2[1]); //undefined |
Hence you cannot use undefined to check if the array is sparse or not
holes are falsy
The holes are falsy in JavaScript.
1 2 3 4 5 6 7 8 9 10 11 | var nums = [0, 1, 2, 3, undefined]; delete nums[1] if (nums[1]) { console.log('Holes are Truthy') //Not Printed } if (!nums[1]) { console.log('Holes are Falsy') } |
Checking if Array is Sparse
The easiest way to check if the array is Sparse is to use the in
operator to test if the index exists in an array. The syntax of the in
operator is shown below.
1 2 3 | index in array |
It will return true if the element exists at the index else return false.
1 2 3 4 5 6 7 | var arr1 = ["Hello",,"World"]; // This is sparse array with no element at index 1 var arr2 = ["Hello",undefined,"World"]; // This array is not sparse. It has a element at index 1 with value undefined console.log(1 in arr1) // => false: arr1 has no element at index 1 console.log(1 in arr2) // => true: arr2 has a element at index 1 |
The following isSparse
function accepts an array as an argument and loops through every index using a for loop.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | function isSparse(array) { for (let i = 0; i < array.length; i++) { if (!(i in array)) { return true; } } return false; } var nums1 = [0, 1, 2, 3]; console.log(isSparse(nums1)) //false delete nums1[1] console.log(isSparse(nums1)) //true |
Note that if you fill-up the holes of a sparse array, it will not become dense but remain sparse internally. There is no easy way to detect such an array.
Convert Sparse Array to Dense Array
The following code uses the for loop to traverse the sparse array and convert it to the dense array.
1 2 3 4 5 6 7 | sparseArray = [, undefined, 1, 2, , 3, ,]; denseArray = []; for(var i = 0; i < sparseArray.length; i++) if(i in sparseArray) denseArray.push(sparseArray[i]); |
We can also use the Object.values() method to convert a sparse array to a dense array. It creates a new array from the object’s own enumerable properties and returns it.
1 2 3 4 5 | const sparseArray = [, , 1, 2, , 3, ,]; const denseArray = Object.values(sparseArray); console.log(denseArray); |
The above methods only remove the holes from the array. They will not remove elements explicitly set to undefined or null.
Array methods and sparse arrays
The array methods in JavaScript treat sparse arrays inconsistently. Some treat them as undefined (usually the newer methods) while others skip them (older methods).
The following methods do not treat them as undefined. How exactly they treat them depends on the method.
concat()
copyWithin()
every()
filter()
flat()
flatMap()
forEach()
indexOf()
lastIndexOf()
map()
reduce()
reduceRight()
reverse()
slice()
some()
sort()
splice()
These methods treat empty slots as if they are undefined
entries()
fill()
find()
findIndex()
findLast()
findLastIndex()
group()
groupToMap()
includes()
join()
keys()
toLocaleString()
values()
Summary
- An array is dense if it has values at every index.
- The array is sparse when its length exceeds the number of elements in it.
- You can create a sparse array by Omitting a value in Array Literal, using Array Constructor, deleting an array element using delete Operator, increasing its Length Property, or Inserting a new value at the index greater than the current length.
- JavaScript treats the sparse array as an object. Hence uses the object property look to locate the value and array index lookup. This makes the sparse array slower.
- Once the array becomes sparse, it will never change back to dense, even if you fill up its empty indexes. The only way is to create a new array using the values from a sparse array.