List transformations in JavaScript
In this tutorial, we will be creating new objects and arrays from existing ones. We will create nested data structures, looping them, and destructuring them. We will also look at transforming data structures by passing them through functions. <!--more-->
Prerequisites
To follow along with this tutorial, it would be helpful to have some background knowledge of JavaScript objects and arrays.
By the end of this tutorial, you will be able to:
- Nest objects and arrays.
- Loop through the nested data structures.
- Destructure nested data structures.
- Transform objects and arrays using underscore.js.
Nesting objects and arrays
Data structures can be nested to avoid the declaration of many variables. Multiple objects and/or arrays can be held by a single variable and can be accessed using dot notation and bracket notation.
const cars = {
'brands': [
{
name: "Ford",
origin: "USA"
},
{
name: "Toyota",
origin: "Japan"
}
]
}
We created an object named cars
and nested an array called brands
inside it. We also added 2 objects inside the brands
array.
Nesting can also be done using either the dot notation or square bracket notation where applicable.
const cars = {};
cars.brands = [];
cars.brands.push({
name: "Ford",
origin: "USA"
});
cars.brands[1] = {
name: "Toyota",
origin: "Japan"
};
Let's break down the code above:
- We created an object
cars
. - We then created an empty array
brands
inside thecars
object using dot notation. - Using the
push()
method, we can add an object with the propertiesname
andorigin
insidebrands
. - Using the square notation adds another object at index 1.
Accessing nested data structures
We can access the first item of the nested array brands
above, using the bracket notation as shown below:
var car1 = cars.brands[0];
console.log(car1); //{ name: "Ford", origin: "USA"}
We can also access the name
property of the first object in the brands
array using the dot notation.
var car1Name = cars.brands[0].name;
console.log(car1Name); //Ford
Looping through nested arrays using a 'for()' loop
Let's loop through all the objects in the nested array brands
we created earlier.
function allCars(brands){
for (let i = 0; i < brands.length; i++){
console.log(brands[i])
};
};
allCars(cars.brands);
//{ name: 'Ford', origin: 'USA' }
//{ name: 'Toyota', origin: 'japan
In the code above:
- We declared a function
allCars()
with a parameter namedbrands
. - We created a
for()
loop inside it that loops throughbrands
and logs them. - We called the function
allCars()
and passed an argumentcars.brands
.
Accessing nested objects properties using a for() loop
We can get common properties in nested objects using a for()
loop. Let's log all the name
properties of the nested brand objects.
function names(brands){
for (var i = 0; i < brands.length; i++){
console.log(brands[i].name)
};
};
names(cars.brands);
//Ford
//Toyota
In the code above:
- We declared the function
names()
, with a parameterbrands
. - We created a for loop that logs each
name
property of the nested objects. - We then called the
names()
function and passed an argumentcars.brands
.
Looping through nested objects properties using a for ...in loop
If we want to get all the properties of a nested object, we can use a for ...in
loop. Let's loop through all the properties of the nested brands
array.
function everything(brands){
for(var i =0; i< brands.length; i++){
for (var property in brands[i]){
console.log(brands[i][property])
}
}
};
everything(cars.brands);
//Ford
//USA
//Toyota
//Japan
In the above code:
- We declared a function named
everything()
with the parameterbrands
. - Inside the
everything()
function, we created afor()
loop that loops through all the items in thebrands
array. - Inside the
for()
loop, we created afor ...in
loop that loops through all the object properties. The for-in loop, assigns each enumerable property of the object to the variablekey
and then logs it. - We called the function
everything()
and pass an argumentcars.brands
.
Destructuring a nested data structure
Destructuring can be used to extract data from nested objects and arrays. We can extract the two brands
objects we created earlier and assign them to new variables.
const {
brands: [
brand1,
brand2
]
} = cars;
console.log(brand1, brand2); //{name: 'Ford', origin: 'USA'} {name: 'Toyota', origin: 'Japan'}
We can also extract the name
and origin
properties from the first object in the brands
array.
const [
{
name,
origin
}
] = cars.brands;
console.log(name, origin) //Ford USA
We extract the name
and origin
properties into variables name
and origin
.
We can also extract all the name
and origin
properties of the objects in the brands
array.
const [
{
name,
origin
},
{
name: name1,
origin: origin1
}
] = cars.brands;
console.log(name, name1, origin, origin1); //Ford Toyota USA Japan
In the code above:
- We extracted the
name
andorigin
properties from the first object into the variablesname
andorigin
. - We assigned the individual object properties to a new variable named
name1
andorigin1
.
We used destructuring to assign the value of the property on the left side (name
) to the variable on the right side (name1
). You can learn more about destructuring here.
List transformations with functions
We can create new objects and arrays by passing existing data structures through the functions. Let's create a function that takes in an array and transforms it to create a new array.
function splitName(name) {
return {
lastName: name.split(' ')[1],
};
};
The function splitName()
takes in some text and splits it using the split()
method, which:
- splits the text by spaces
- returns an array with the split pieces of text
splitName()
then accesses the 2nd item in the array and assigns it as the value of lastName
in the splitName()
return object.
Let's create an array that will be passed to this function.
var namesList = ['Jon Doe', 'Jane Dove', 'Joe Bloggs'];
We also need an array to hold the values from splitName
. Let's create this variable.
var halfNames = [];
To pass all the items in the names
array to splitName()
, we'll use a for
loop.
for(var i = 0; i < namesList.length; i++){
nameObj = splitName(namesList[i])
halfNames.push(nameObj);
}
console.log(halfNames); //[ { lastName: 'Doe' }, { lastName: 'Dove' }, { lastName: 'Bloggs' } ]
The for
loop above:
- Loops through
namesList
array. - Passes each item in
namesList
throughsplitName()
. - Using the
push()
method to add the objects returned bysplitName()
to thehalfNames
array.
We can reduce the lines of code in the for
loop above by calling splitName()
inside the push()
method.
for(var i = 0; i < namesList.length; i++){
halfNames.push(splitName(namesList[i]));
}
console.log(halfNames); //[ { lastName: 'Doe' }, { lastName: 'Dove' }, { lastName: 'Bloggs' } ]
List transformations using underscore.js
Underscore.js is a JavaScript library that provides many methods and functions for dealing with arrays, objects and functions. It can be used to do many operations with a few lines of code.
To run underscore.js on a browser, import it under <script>
html tags as shown below.
<script src="https://pagecdn.io/lib/underscore/1.11.0/underscore-min.js" type="text/javascript"></script>
You can install it in Node.js via npm.
$ npm install underscore
To use underscore.js in our code, we'll need to initialize it. We do this in Node.js, by adding the following code at the top of the file.
var _ = require('underscore');
Looping with _.each()
_.each()
is an underscore.js function that is used to loop through and perform actions to lists.
It takes two arguments:
- The iteratee, which is a list of objects.
- A callback function.
The code below shows looping through an array using the _.each()
function.
const numbers = ['one', 'two', 'three'];
_.each(numbers, function(number){
console.log(number)
}
);
//one
//two
//three
The function _.each()
above:
- Loops through the
numbers
array passing each number to the callback function. - The callback function then logs each number to the console.
Looping with _.map()
_.map()
is an underscore.js function that produces new arrays by passing each value in a list through a transformation function.
It takes two arguments:
- The iteratee, which is a list of objects.
- A transformation function.
The code below shows looping through an array of numbers using _.map()
.
const numbersList = [2,4,6,8];
var doubleNumbers = _.map(numbersList, function(number){
return number * 2
}
);
console.log(doubleNumbers); //[ 4, 8, 12, 16 ]
In the above code:
_.map()
loops throughnumbersList
passing each number into the transformation function.- The transformation function then multiplies the number by 2.
- The resulting array is then stored as
doubleNumbers
.
_.map()
can also be used to transform objects.
const numberObj = {1: 'one', 2: 'two', 3: 'three'};
var doubleNumbers = _.map(numberObj,function(value, key){
return key*2
}
);
console.log(doubleNumbers); //[ 2, 4, 6 ]
In the code above:
_.map()
loops through all the properties of the iteratee (numberObj
) passing each to the transformation function. The properties passed are inverted i.e. the key becomes the value.- The function multiplies the
key
of the passed property by 2. - The resulting values are then saved as an array
doubleNumbers
.
Filtering data using _.filter()
_.filter()
is an underscore.js function that returns a list of objects that pass a certain condition. This function can be used to find certain properties in a large array. The function takes two arguments:
- The iteratee, which is a list of objects.
- A predicate, which is a function holding the truth condition.
We can filter all odd numbers in an array of numbers using _.filter()
as shown below:
const numbersList = [1,2,3,4,5,6,7,8,9,10];
var oddsList = _.filter(numbersList, function(number){
return number % 2 !== 0
}
);
console.log(oddsList); //[ 1, 3, 5, 7, 9 ]
In the code above:
- We passed a list of numbers
numbersList
to_.filter()
. - We then declared a predicate function that took in a
number
and checked whether the number is divisible by 2. - The numbers that pass the conditions above are saved as
oddsList
.
We can also filter a nested array.
var peopleList = [
{
name: 'john',
age: 20,
},
{
name: 'Jane',
age: 17
},
{
name: 'Peter',
age: 22,
}
]
var adultsList = _.filter(peopleList, function(personObject){
return personObject.age > 18
});
console.log(adultsList); //[ { name: 'john', age: 20 }, { name: 'Peter', age: 22 } ]
In the code above:
- We created a nested array of objects
peopleList
. - We passed
peopleList
to_.filter()
. - We then declared a predicate function that took in a
personObject
and checks if the propertyage
was greater than the value 18. - The objects that pass the above conditions are then saved as
adultsList
.
Conclusion
We have looked at the various methods used for list transformations. There are other methods other than the ones mentioned. Underscore.js has many more easy to read and implement functions. I would recommend you check them out on their website.
Peer Review Contributions by: Adrian Murage