Converting and Transforming Arrays in JavaScript

Arrays are a fundamental and powerful data structure in programming. Their power doesn’t just come from their ability to store multiple objects or values. They also expose a variety of tools that make it easy to manipulate and work with the data they contain.

We often need to change an array to meet a specific need. For example, you may need to reorganize the objects in an array so that it is sorted by the value of a particular property, or you may need to merge multiple arrays into a single array. In many cases, you may need to completely transform an array of objects into another array of completely different objects.

In this tutorial, you will learn about the tools JavaScript provides to merge, copy, convert, and filter arrays. Before we begin, however, it is important that I point out that while I use the terms “merge”, “convert”, “transform”, and “filter”, very rarely do these processes change an existing array. Instead, they create a new array that contains the merged, converted, transformed, and filtered data—leaving the original array in its unchanged and pristine format.

Merging Arrays

Perhaps you are working with data that comes from different sources, or you may have multiple arrays and want to combine them into a single array to make it easier to process them. Regardless of your reasons, sometimes you need to combine multiple arrays into a single array. JavaScript gives us two ways to combine arrays. You can either use the concat() method or the spread operator (...).

The concat() method is used to merge two or more arrays and returns a new array containing the elements of the joined arrays. The new array will first be populated by the elements in the array object on which you call the method. It will then be populated by the elements of the array objects you pass to the method. For example:

1
const array1 = [1, 2, 3];
2
const array2 = [4, 5, 6];
3
const mergedArray = array1.concat(array2);
4
console.log(mergedArray); // output: [1, 2, 3, 4, 5, 6]

In this code, we have two arrays, array1 and array2. We merge these arrays into a new array called mergedArray using the concat() method, and you can see the resulting array contains the elements [1, 2, 3, 4, 5, 6].  The example below alters the code so that the concat() method is called on array2:

1
const array1 = [1, 2, 3];
2
const array2 = [4, 5, 6];
3
const mergedArray2 = array2.concat(array1);
4
console.log(mergedArray2); // output: [4, 5, 6, 1, 2, 3]

Notice that in this code, the elements in the resulting array are in a different order: [4, 5, 6, 1, 2, 3]. So, if element order is important to you, be sure to use concat() in your desired order. 

The spread operator, on the other hand, allows you to expand the elements of an array, and it can be used within a new array literal to merge arrays. For example:

1
const array1 = [1, 2, 3];
2
const array2 = [4, 5, 6];
3
const mergedArray = [...array1, ...array2];
4
console.log(mergedArray); // output: [1, 2, 3, 4, 5, 6]

Here, we again have two arrays, array1 and array2, but we merge them into a new array called mergedArray using the spread operator. The end result is the same as the first concat() example, but using this approach gives you (and those reading your code) a clearer understanding of how the mergedArray is built and populated.

Copying Arrays

There are several reasons why you may want to copy an array. You may want to preserve an array’s original data (if they are simple values), or you may want to avoid any unintended side effects of working with or manipulating an array object itself. Regardless of the reason, JavaScript makes it very easy to create a copy of an array.

To create a copy of an array, you can use the slice() method. This method returns a shallow copy (more on that later) of the array you call it on. For example:

1
const originalArray = [1, 2, 3, 4, 5];
2
const copiedArray = originalArray.slice();
3

4
console.log(copiedArray); // output: [1, 2, 3, 4, 5]

This code defines an array called originalArray, and we create a copy of it using the slice() method without passing any arguments. The copiedArray object contains the same values as the original, but it is a completely different array object.

You can also use the slice() method to extract a portion of an array by specifying the start and end indices.

1
const originalArray = [1, 2, 3, 4, 5];
2
const slicedArray = originalArray.slice(1, 4);
3

4
console.log(slicedArray); // output: [2, 3, 4]

In this example, we create a sliced array that contains the elements from index 1 to index 3 (the end index passed to the slice() method is not included) of the original array.

What Is a Shallow Copy?

A shallow copy refers to creating a new object or array that is a copy of the original object or collection, but only at the first level. In other words, a shallow copy duplicates the structure of the original object, but not the objects or elements contained within it.

When you create a shallow copy of an array, the new array will have its own set of references to the same objects or elements as the original array. This means that if the original array contains simple values (e.g. numbers, strings, or booleans), the shallow copy will effectively create a new array with the same values. However, if the original array contains objects or other reference types (such as other arrays or objects), the shallow copy will only copy the references to those objects—not the objects themselves. As a result, any changes made to the objects within the original array will also be reflected in the shallow copy and vice versa, since they still refer to the same objects in memory.

In contrast, a deep copy creates a new object or collection that is a complete, independent copy of the original object or collection, including all the nested objects or elements. This means that changes made to the objects within the original array will not affect the deep copy, and vice versa, as they have their own set of objects in memory.

Here’s an example to illustrate the difference:

1
const originalArray = [1, 2, { a: 3 }];
2
const shallowCopy = originalArray.slice();
3
const deepCopy = JSON.parse(JSON.stringify(originalArray));
4

5
originalArray[2].a = 4;
6

7
console.log(shallowCopy); // output: [1, 2, { a: 4 }]
8
console.log(deepCopy); // output: [1, 2, { a: 3 }]

In this example, the shallowCopy reflects the changes made to the original array, while the deepCopy remains unaffected.

Converting Arrays to Strings

Arrays are a programming construct, and there are many times when we need to convert the array into a string. Maybe we need to present an array’s contents to the user. Perhaps we need to serialize the contents of an array into a format other than JSON.

By using the join() method, you can convert an array to a string. By default, the elements are separated by a comma, but you can specify a custom separator by passing a string as an argument to the join() method. For example:

1
const fruitArray = ['apple', 'banana', 'cherry'];
2
const fruitString = fruitArray.join(', ');
3

4
console.log(fruitString); // output: "apple, banana, cherry"

In this example, we have an array called fruitArray, and we convert it to a string using the join() method with a custom separator—a comma followed by a space.

A more useful example of using join() is to output a URL query string from an array that contains URL query string parameters, as shown here:

1
const queryParamsArray = [
2
  'search=JavaScript',
3
  'page=1',
4
  'sort=relevance',
5
];
6

7
const queryString = queryParamsArray.join('&');
8

9
const url = 'https://example.com/api?' + queryString;
10
console.log(url); // output: "https://example.com/api?search=JavaScript&page=1&sort=relevance"

In this code, we have an array called queryParamsArray that contains a set of query string parameters. We then use the join() method to concatenate the elements of the array with the & delimiter to form a query string. Finally, we construct the complete URL by appending the query string to the base URL.

Generating URL query parameter strings is a common use case for using join(). However, instead of simple, predefined strings as shown in this example, you’d work with an array of complex objects that you’d then have to transform into an array of strings that you can join together.

Transforming Arrays

The ability to transform an array is one of the most useful and powerful features in JavaScript. As I mentioned earlier in this tutorial, you aren’t really transforming an array—you are creating a new array that contains the transformed objects or values. The original array is not modified.

To transform an array, you use the map() method. It accepts a callback function as an argument, and it executes that function for every element in the array.

1
map(function (currentElement[, index, array]));

The callback function can accept the following three arguments:

  • currentElement: the current element to transform (required)
  • index: the index of the current element (optional)
  • array: the array the map() method is called on (optional)

The callback function’s return value is then stored as an element in the new array. For example:

1
const numbers = [1, 2, 3, 4, 5];
2

3
function square(number) {
4
  return number * number;
5
}
6

7
const squaredNumbers = numbers.map(square);
8

9
console.log(squaredNumbers); // output: [1, 4, 9, 16, 25]

In this code, we have an array called numbers, and we declare a function called square that takes a number as input and returns the square of that number. We pass the square function to numbers.map() to create a new array, called squaredNumbers, that contains the squared values of the original numbers.

But let’s look at an example that builds a URL query string from an array of objects. The original array will contain objects that have param (for the parameter name) and value (for the parameter value) properties.

1
const queryParams = [
2
  { param: 'search', value: 'JavaScript' },
3
  { param: 'page', value: 1 },
4
  { param: 'sort', value: 'relevance' },
5
];
6

7
function createParams(obj) {
8
  return obj.param + '=' + obj.value;
9
}
10

11
const queryStringArray = queryParams.map(createParams);
12

13
const queryString = queryStringArray.join('&');
14

15
const url = 'https://example.com/api?' + queryString;
16
console.log(url); // output: "https://example.com/api?search=JavaScript&page=1&sort=relevance"

In this example, we have an array called queryParams that contains objects that we want to convert into a query string. We declare a function called createParams that accepts an object as input and returns a string in the format “param=value“. Then, we create a new array called queryStringArray by applying the createParams function to each object in the original array using the map() method.

Next, we join() the queryStringArray to create the final query string, using the & delimiter to separate each param=value pair, and then we construct the complete URL by appending the query string to the base URL.

Using the map() method is a vital part of working with arrays, but sometimes we only need to work with a few elements within an array.

Filtering Arrays

The filter() method allows you to create a new array that contains only the elements that satisfy a given condition. This is achieved by passing a callback function to the filter() method which tests each element in the original array. If the callback function returns true, the element is included in the new array; if it returns false, the element is excluded.

The callback function uses the same signature as the map() method’s callback function:

1
filter(function(currentElement[, index, array]));

The currentElement parameter is required, but index and array are optional. For example:

1
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
2

3
function isEven(number) {
4
  return number % 2 === 0;
5
}
6

7
const evenNumbers = numbers.filter(isEven);
8

9
console.log(evenNumbers); // output: [2, 4, 6, 8, 10]

In this example, we have an array called numbers. We declare a function called isEven that takes a number as input and returns true if the number is even (i.e. divisible by 2) or false otherwise. We create a new array called evenNumbers by filtering the original array using the isEven function as the callback function for the filter() method. The resulting evenNumbers array contains only the even numbers from the original array.

The filter() method is a powerful tool for processing arrays, allowing you to easily extract relevant data or create subsets of an array based on specific criteria.

Conclusion

Arrays are one of the most versatile and useful objects in JavaScript because we have the tools to easily merge, copy, convert, transform, and filter them. Each of these techniques serves a specific purpose, and you can combine them in various ways to effectively manipulate and process arrays in your JavaScript applications. By understanding and applying these methods, you’ll be better equipped to tackle a wide range of programming challenges that involve working with arrays.

As you continue to develop your JavaScript skills, remember to practice using these array methods and explore other built-in array functions available in the language. This will help you become more proficient in JavaScript and enable you to write more efficient, clean, and maintainable code. Happy coding!


Source link