When we scratch beyond the surface of what arrays are capable of, we enter into some unchartered territory - even if what we are doing seems very reasonable. In this short article, let's chart the unknown and look at how we would accomplish some common array-related tasks such as:
If any of these seem particularly interesting, click on the heading to check it out directly. If not, just read on for some totally-not-boring tricks about our friendly, neighborhood array.
Onwards!
To kick your array skills into the stratosphere, everything you need to be an arrays expert is available in this book.
BUY ON AMAZONIf you want to copy or clone an array to a new variable, you will need to use the slice method without specifying any arguments:
let foo = ["fee", "fi", "fo", "fum"];
let fooCopy = foo.slice();
console.log(fooCopy);
In this example, fooCopy contains a full copy of all the items in the foo array.
For detecting whether an item is an array or not, the hip way that all the cool kids (like senocular) use is Array.isArray:
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
console.log(Array.isArray(numbers)); // true
If you are old-school, you can also check the constructor property on whatever array-like object to see if its value is an Array or not:
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// Array
console.log(numbers.constructor === Array);
let name = "Homer Simpson";
// Not an array
console.log(name.constructor === Array);
Notice that we are checking for the Array type directly as opposed to the string-based name for it.
While it is easy to add an item to the array, there is no built-in equivalent for removing an item you've added. You'll need to rely on indexOf and splice to create your own remove functionality:
let evenNumbers = [0, 2, 4, 6, 7, 8, 10];
console.log(evenNumbers.length) // 7 items
let removeIndex = evenNumbers.indexOf(7);
if (removeIndex > -1) {
evenNumbers.splice(removeIndex, 1);
}
console.log(evenNumbers.length) // 6 items
console.log(evenNumbers);
This approach will completely remove any trace of the array item ever having existed.
For a less intrusive approach, you have the delete keyword. If you try to delete an item from an array using it, the behavior is a bit different. Take a look at the following code snippet to see what happens:
let evenNumbers = [0, 2, 4, 6, 7, 8, 10];
console.log(evenNumbers.length) // 7 items
let removeIndex = evenNumbers.indexOf(7);
delete evenNumbers[removeIndex];
console.log(evenNumbers.length) // 7 items
console.log(evenNumbers);
The only thing that happens using the delete keyword is that the removed item is set to an empty value, but an array entry still remains. That entry will now reference an empty item. The length of the items in the array is still the same as well. That may not be what you expect. If we inspect the output of the above code, here is what evenNumbers will print to our console:
[0, 2, 4, 6, empty, 8, 10]
Where our odd 7 number was, you will see empty instead. The takeaway is this. If you want to retain all of your array indexes, use the delete keyword when you want to remove an item. If you want to fully remove an item and any trace of it from your array, use the indexOf and splice approach instead.
To empty out and delete all the contents from your array, the simplest (and also the fastest-ish!) way is to use the totally nonintuitive approach where you set the length property of your array to 0:
let myItems = ["apples", "oranges", "bananas", "kiwis"];
console.log(myItems.length); // 4
myItems.length = 0;
console.log(myItems.length); // 0
I know this looks absolutely ridiculous, but try it out for yourself. It totally works!
Thanks to ES6 and the Set object, removing duplicate values from your array is pretty straightforward:
let names = ["Peter", "Joe", "Cleveland", "Quagmire", "Joe"];
let uniqueNames = [...new Set(names)];
console.log(uniqueNames);
The trick is to use the spread (...) operator that expands a collection of items into its individual pieces. There is one wrinkle with this approach. In my testing, the performance of this approach is much slower than the more verbose approach described here. You can see for yourself by running the jsperf test.
Arrays in JavaScript come with a handy built-in sort method that allows you to specify exactly how to sort. Take a look at the following example where we are sorting some numbers as well as text:
let numbers = [3, 10, 2, 14, 7, 2, 9, 5];
let beatles = ["Ringo", "George", "Paul", "John"];
numbers.sort(compareValues);
beatles.sort(compareValues);
function compareValues(a, b) {
if (a < b) {
// if a less than b
return -1;
} else if (a > b) {
// if a greater than b
return 1;
} else {
// a and b are equal
return 0;
}
}
console.log(numbers);
console.log(beatles);
We are using one comparison function called compareValues. This function (a callback function to be precise) compares two values that are passed in as an argument, and all we have to do is specify which of the two values should appear first. We do that by returning either -1, 1, or 0. Returning -1 means the first value will appear ahead of the second value. Returning 1 means the first value will appear after the second value. Returning 0 means both values are equal.
Our compareValues function is pretty straightforward. For more involved types of data, you'll need to customize your comparison function appropriately, but even that isn't rocket science. Below is an example of sorting an array of Objects:
let shows = [
{
name: "Frasier",
seasons: 11
},
{
name: "Seinfeld",
seasons: 9
},
{
name: "Friends",
seasons: 10
},
{
name: "Cheers",
seasons: 11
},
{
name: "Animaniacs",
seasons: 5
},
{
name: "Everybody Loves Raymond",
seasons: 9
}
];
function showComparison(a, b) {
if (a.seasons < b.seasons) {
// if a less than b
return -1;
} else if (a.seasons > b.seasons) {
// if a greater than b
return 1;
} else {
// a and b are equal
return 0;
}
}
let sortedShows = shows.sort(showComparison);
console.log(sortedShows);
In this example, we are sorting television shows by the number of seasons. Each television show is represented as an Object in our array. Notice how we have our showComparison function defined. Instead of comparing the two values directly, we are dotting into the seasons value to help determine which show should appear first.
If you want to spice things up, you can randomly rearrange all the contents of our array. To do that, you can use the following shuffling code:
Array.prototype.shuffle = function () {
let input = this;
for (let i = input.length - 1; i >= 0; i--) {
let randomIndex = Math.floor(Math.random() * (i + 1));
let itemAtIndex = input[randomIndex];
input[randomIndex] = input[i];
input[i] = itemAtIndex;
}
return input;
}
The way you would use it is as follows:
let tempArray = [1, 2, 3, 4, 5, 6, 7, 8, 9];
tempArray.shuffle();
// and the result is...
console.log(tempArray);
To learn more about how this code works and the role a few people whose last names are Fisher, Yates, and Knuth played in its creation, read the Shuffling an Array article.
If you need to select an item at random from our array, we can combine some of the concepts from the Random Numbers article and apply it to our array-centric world. The snippet would be:
let value = myArray[Math.floor(Math.random() * myArray.length)];
Here is a fuller example:
let myArray = ["Unos", "Dos", "Tres", "Catorce"];
let value = myArray[Math.floor(Math.random() * myArray.length)];
console.log(value);
To learn more on how this code works, the Picking a Random Item from an Array article goes into more detail.
When you have multiple arrays and you want to combine them into a single array, you have a way of doing that by using the spread operator. Take a look at the following example:
let smileys = ["😀", "😇", "😛", "🥶"];
let foods = ["🍊", "🥦", "🍔", "🍕", "🍰"];
let animals = ["🐙", "🐝", "🐈"];
let combined = [...smileys, ...foods, ...animals];
console.log(combined);
We have three arrays called smileys, foods, and animals. By using the spread operator (aka ...), we flatten these arrays into individual items and store the merged contents under the new array called combined.
By the way, if this is the first time you are seeing emojis inside an array and are a bit puzzled by it, don't worry. This is totally normal and the Using Emojis in HTML, CSS, and JS article dives further into this wonderful act of nature.
If you want to swap two items in an array, there are several ways to go about doing this. The quickest approach is to do something as follows:
let myData = ["a", "b", "c", "d", "e", "f", "g"];
let temp = myData[2];
myData[2] = myData[5];
myData[5] = temp;
console.log(myData); // a b f d e c g
For something a bit more reusable, we can use a function whose job it is to swap the items of an array:
let myData = ["a", "b", "c", "d", "e", "f", "g"];
function swap(input, index_A, index_B) {
let temp = input[index_A];
input[index_A] = input[index_B];
input[index_B] = temp;
}
swap(myData, 2, 5);
console.log(myData); // a b f d e c g
The swap function works by taking three arguments:
When we pass these three arguments in, the end result is that our specified array will get the items at the specified index positions swapped. If we want to go one step even further, we can extend our Array object with this swapping capability. You can learn more about that and how we generally approached this swapping problem in the Swapping Items in an Array article.
The relationship between arrays and objects has always been a bit scandalous. They both allow us to store arbitrary amounts of data. They both have a way of indexing the items. Deep down, an Array is itself an Object...just like everything else in JavaScript. Now, if you ever have the desire to go from an array to an object, the following snippet is for you:
let airportCodes = ["SFO", "LAX", "SEA", "NYC", "ORD", "ATL"];
let airportCodesObject = { ...airportCodes };
console.log(airportCodesObject);
The airportCodesObject will look as follows:
The original array item's index position will be the key, and the corresponding array item's content will be the value.
We have the ability to reverse the order items appear in our array by using the built-in reverse method:
let numbers = [1, 2, 3, 4, 5, 6];
numbers.reverse();
console.log(numbers);
The reverse method does modify our original array itself. If you wish to preserve our original array and create a new reversed array instead, we can do the following:
let numbers = [1, 2, 3, 4, 5, 6];
let reversed = [...numbers].reverse();
console.log(reversed);
Yes, the spread operator turns out to be quite the jack-of-all-trades when it comes to dealing with arrays.
Arrays have the handy every method that allows us to check if all items in an array pass a test that we specify. For example, the following snippet uses the every method and an isEven function to check if all items in our someNumbers array are even:
let someNumbers = [2, 4, 38, 20, 10, 13, 42];
function isEven(currentItem) {
if (currentItem % 2 === 0) {
return true;
}
}
console.log(someNumbers.every(isEven));
// false
Because not all of the items in our someNumbers array are even (looking at you 13), the result is false.
In the previous trick, we saw how the every method returns a true only if all items in the array pass our test. The some method is less picky. This method will return a true if any items in our array pass our test. Take a look at the following example:
let highScores = [46, 191, 38, 10, 156];
function isReallyHighScore(currentItem) {
if (currentItem > 100) {
return true;
}
}
console.log(highScores.some(isReallyHighScore));
// true
We have an array of high scores, and the isReallyHighScore function checks if any of the scores are greater than 100. Combining all of this with the some method, the result is true because the values 191 and 156 are indeed greater than 100. It's ok that not all of the scores are greater than 0. That's just how the some method rolls.
Having nested arrays where our arrays are made up of items that themselves are arrays is a common thing:
let cool = [1, 2, [1, 2, [1, 2]]];
The term multidimensional array might come to mind. In some cases, having nested arrays isn't desirable and more of a side effect of how our data got there. Web requests with complex JSON data is a great example of this. In these cases, we may want to flatten our arrays into something manageable. We can do this with the flat method and passing in a number for the levels of depth to flatten by:
let cool = [1, 2, [1, 2, [1, 2]]];
let flatCool = cool.flat(1);
console.log(flatCool); // [1, 2, 1, 2, [1, 2]]
In this example, our cool array has two levels of nested arrays. By specifying depth value of 1, we tell our flat method to flatten our arrays by one layer, leaving only one layer of nested arrays behind. There will be times when you want to flatten your arrays fully, so you can specify a higher numerical value for the depth. If you have no idea how deep your arrays are nested, you can throw down the ultimate value for the depth to flatten any array of any depth:
let cool = [1, 2, [[[[[1]]]], 2, [1, 2]]];
let flatCool = cool.flat(Infinity);
console.log(flatCool); // [1, 2, 1, 2, 1, 2]
That's right! You can specify a depth value of Infinity to the flat method, and that will ensure your array is flattened in all situations.
When working with external data, the values we get often get changed to be strings. This happens with arrays all the time where a collection of numbers is returned to us a collection of strings. To change all of the items back to a number, we can use map and the Number object:
let original = ["1", "2", "3", "4", "5"];
let arrayOfNumbers = original.map(Number);
console.log(arrayOfNumbers); // [1, 2, 3, 4, 5]
This approach works for a bunch of other situations as well. If we want to do the opposite where we want to go from numbers back to strings, this what we can do:
let numbers = [1, 2, 3, 4, 5];
let arrayOfStrings = numbers.map(String);
console.log(arrayOfStrings); // ['1', '2', '3', '4', '5']
You can try this with other data types as well. Another common situation is turning a collection of boolean (true / false) values into strings...or vice versa.
Whew. That's a lot of random array-related stuff to digest, but these tricks will come in handy given how often you will use arrays in your day-to-day coding life. I guarantee it. If there are additional array tricks that you know about that I didn't cover, jump into the comments and post them.
Just a final word before we wrap up. If you have a question and/or want to be part of a friendly, collaborative community of over 220k other developers like yourself, post on the forums for a quick response!
:: Copyright KIRUPA 2024 //--