Let’s Explore ES6 Destructuring in JavaScript

JavaScript is currently one of the most used programming languages in the world, being used across different platforms ranging from web browsers, mobile devices, VR, web servers, etc. Although the language has not changed a lot through the years when compared to other programming languages, there are some recent changes that are worth taking note of, because of the expressive power they add to the language — some of which are: template literals, destructuring, spread operator, arrow functions, classes, etc.

In this tutorial, our major focus will be on learning how to harness the power of destructuring to simplify our JavaScript programs. Before we dive into the what and how of destructuring I think the why should be considered. If you already use TypeScript or a modern JavaScript framework like React, Vue, Preact, Angular, etc, you may already be familiar with destructuring. However, there is a possibility that by going through this tutorial, you may learn a few new stuffs about destructuring you may not have known.

For this tutorial, it is assumed you already have some prior experience writing JavaScript code. There is a chance that some of the code snippets may not work on your browser depending on the version of the browser, since all the ES6 and ES7 features are not yet fully supported in all browsers. You may opt to test the code snippets on Codepen or your favorite online JavaScript live editor. Another alternative would be using the Babel transpiler to get it to work on your browser.

Why Destructuring?

To explain the why of destructuring, we will consider a scenario which most of us might be familiar with or might have come across at one time or the other when coding in JavaScript. Imagine we have the data of a student including scores in three subjects(Maths, Elementary Science, English) represented in an object and we need to display some information based on this data. We could end up with something that looks like this:

const student = {
    name: 'John Doe',
    age: 16,
    scores: {
        maths: 74,
        english: 63,
        science: 85
    }
};

function displaySummary(student) {
    console.log('Hello, ' + student.name);
    console.log('Your Maths score is ' + (student.scores.maths || 0));
    console.log('Your English score is ' + (student.scores.english || 0));
    console.log('Your Science score is ' + (student.scores.science || 0));
}

displaySummary(student);

// Hello, John Doe
// Your Maths score is 74
// Your English score is 63
// Your Science score is 85

With the above code snippet, we would achieve the desired result. However, there are a few caveats to writing code this way. One of which is — you can easily make a typo and instead of writing scores.english for example, you write score.english which will result in an error. Again, if the scores object we are accessing is deeply nested in another object, the object access chain becomes longer which could mean more typing. These may not seem to be much an issue, but with destructuring we can do the same in a more expressive and compact syntax.

What is Destructuring?

Destructuring simply implies breaking down a complex structure into simpler parts. In JavaScript, this complex structure is usually an object or an array. With the destructuring syntax, you can extract smaller fragments from arrays and objects. Destructuring syntax can be used for variable declaration or variable assignment. You can also handle nested structures by using nested destructuring syntax.

Using destructuring, the function from our previous snippet will look like this:

function displaySummary({ name, scores: { maths = 0, english = 0, science = 0 } }) {
    console.log('Hello, ' + name);
    console.log('Your Maths score is ' + maths);
    console.log('Your English score is ' + english);
    console.log('Your Science score is ' + science);
}

There is a chance that the code in the last snippet didn’t go down well with you. If that’s the case, then follow up with the tutorial till you get to the end — I assure you it will all make sense. Let’s continue to learn how we can harness the power of destructuring.

Object Destructuring

What we saw in that last snippet is a form of object destructuring being used as an assignment to a function. Let’s explore what we can do with object destructuring starting from the ground up. Basically, you use an object literal on the left-hand-side of an assignment expression for object destructuring. Here is a basic snippet:

const student = {
    firstname: 'Glad',
    lastname: 'Chinda',
    country: 'Nigeria'
};

// Object Destructuring
const { firstname, lastname, country } = student;

console.log(firstname, lastname, country); // Glad Chinda Nigeria

Here we used object destructuring syntax to assign values to three variables: firstname, lastname and country using the values from their corresponding keys on the student object. This is the most basic form of object destructuring.

The same syntax can be used in variable assignment as follows:

// Initialize local variables
let country = 'Canada';
let firstname = 'John';
let lastname = 'Doe';

const student = {
    firstname: 'Glad',
    lastname: 'Chinda',
    country: 'Nigeria'
};

// Reassign firstname and lastname using destructuring
// Enclose in a pair of parentheses, since this is an assignment expression
({ firstname, lastname } = student);

// country remains unchanged (Canada)
console.log(firstname, lastname, country); // Glad Chinda Canada

The above snippet shows how to use object destructuring to assign new values to local variables. Notice that we had to use a pair of enclosing parentheses (**()**) in the assignment expression. If omitted, the destructuring object literal will be taken to be a block statement, which will lead to an error because a block cannot appear at the left-hand-side of an assignment expression.

Default Values

Trying to assign a variable corresponding to a key that does not exist on the destructured object will cause the value undefined to be assigned instead. You can pass default values that will be assigned to such variables instead of undefined. Here is a simple example.

const person = {
    name: 'John Doe',
    country: 'Canada'
};

// Assign default value of 25 to age if undefined
const { name, country, age = 25 } = person;

// Here I am using ES6 template literals
console.log(`I am ${name} from ${country} and I am ${age} years old.`);

// I am John Doe from Canada and I am 25 years old.'

Here we assigned a default value of 25 to the age variable. Since the age key does not exist on the person object, 25 is assigned to the age variable instead of undefined.

Using Different Variable Names

So far, we have been assigning to variables that have the same name as the corresponding object key. You can assign to a different variable name using this syntax: **[object_key]:[variable_name]**. You can also pass default values using the syntax: **[object_key]:[variable_name] = [default_value]**. Here is a simple example.

const person = {
    name: 'John Doe',
    country: 'Canada'
};

// Assign default value of 25 to years if age key is undefined
const { name: fullname, country: place, age: years = 25 } = person;

// Here I am using ES6 template literals
console.log(`I am ${fullname} from ${place} and I am ${years} years old.`);

// I am John Doe from Canada and I am 25 years old.'

Here we created three local variables namely: fullname, place and years that map to the name, country and age keys respectively of the person object. Notice that we specified a default value of 25 for the years variable in case the age key is missing on the person object.

Nested Object Destructuring

Referring back to our initial destructuring example, we recall that the scores object is nested in the student object. Let’s say we want to assign the Maths and Science scores to local variables. The following code snippet shows how we can use nested object destructuring to do this.

const student = {
    name: 'John Doe',
    age: 16,
    scores: {
        maths: 74,
        english: 63
    }
};

// We define 3 local variables: name, maths, science
const { name, scores: {maths, science = 50} } = student;

console.log(`${name} scored ${maths} in Maths and ${science} in Elementary Science.`);

// John Doe scored 74 in Maths and 50 in Elementary Science.

Here, we defined three local variables: name, maths and science. Also, we specified a default value of 50 for science in case it does not exist in the nested scores object. Notice that, scores is not defined as a variable. Instead, we use nested destructuring to extract the maths and science values from the nestedscores object.

When using nested object destructuring, be careful to avoid using an empty nested object literal. Though it is valid syntax, it actually does no assignment. For example, the following destructuring does absolutely no assignment.

// This does no assignment
// Because of the empty nested object literal ({})
const { scores: {} } = student;

Array Destructuring

By now you are already feeling like a destructuring ninja, having gone through the rigours of understanding object destructuring. The good news is that array destructuring is very much similar and straight forward so let’s dive in right away.

In array destructuring, you use an array literal on the left-hand-side of an assignment expression. Each variable name on the array literal maps to the corresponding item at the same index on the destructured array. Here is a quick example.

const rgb = [255, 200, 0];

// Array Destructuring
const [red, green, blue] = rgb;

console.log(`R: ${red}, G: ${green}, B: ${blue}`); // R: 255, G: 200, B: 0

In this example, we have assigned the items in the rgb array to three local variables: red, green and blue using array destructuring. Notice that each variable is mapped to the corresponding item at the same index on the rgb array.

Default Values

If the number of items in the array is more than the number of local variables passed to the destructuring array literal, then the excess items are not mapped. But if the number of local variables passed to the destructuring array literal exceed the number of items in the array, then each excess local variable will be assigned a value of undefined except you specify a default value.

Just as with object destructuring, you can set default values for local variables using array destructuring. In the following example, we would set default values for some variables in case a corresponding item is not found.

const rgb = [200];

// Assign default values of 255 to red and blue
const [red = 255, green, blue = 255] = rgb;

console.log(`R: ${red}, G: ${green}, B: ${blue}`); // R: 200, G: undefined, B: 255

You can also do an array destructuring assignment. Unlike with object destructuring, you don’t need to enclose the assignment expression in parentheses. Here is an example.

let red = 100;
let green = 200;
let blue = 50;

const rgb = [200, 255, 100];

// Destructuring assignment to red and green
[red, green] = rgb;

console.log(`R: ${red}, G: ${green}, B: ${blue}`); // R: 200, G: 255, B: 50

Skipping Items

It is possible to skip some items you don’t want to assign to local variables and only assign the ones you are interested in. Here is an example of how we can assign only the blue value to a local variable.

const rgb = [200, 255, 100];

// Skip the first two items
// Assign the only third item to the blue variable
const [,, blue] = rgb;

console.log(`Blue: ${blue}`); // Blue: 100

We used comma separation(,) to omit the first two items of the rgb array, since we only needed the third item.

Swapping Variables

One very nice application of array destructuring is in swapping local variables. Imagine you are building a photo manipulation app and you want to be able to swap the height and width dimensions of a photo when the orientation of the photo is switched between landscape and portrait. The old-fashioned way of doing this will look like the following.

let width = 300;
let height = 400;
const landscape = true;

console.log(`${width} x ${height}`); // 300 x 400

if (landscape) {
    // An extra variable needed to copy initial width
    let initialWidth = width;

    // Swap the variables
    width = height;
  
    // height is assigned the copied width value
    height = initialWidth;

    console.log(`${width} x ${height}`); // 400 x 300
}

The above code snippet performs the task, although we had to use an additional variable to copy the value of one of the swapped variables. With array destructuring, we can perform the swap with a single assignment statement. The following snippet shows how array destructuring can be used to achieve this.

let width = 300;
let height = 400;
const landscape = true;

console.log(`${width} x ${height}`); // 300 x 400

if (landscape) {
    // Swap the variables
    [width, height] = [height, width];
  
    console.log(`${width} x ${height}`); // 400 x 300
}

Nested Array Destructuring

Just as with objects, you can also do nested destructuring with arrays. The corresponding item must be an array in order to use a nested destructuring array literal to assign items in it to local variables. Here is a quick example to illustrate this.

const color = ['#FF00FF', [255, 0, 255], 'rgb(255, 0, 255)'];

// Use nested destructuring to assign red, green and blue
const [hex, [red, green, blue]] = color;

console.log(hex, red, green, blue); // #FF00FF 255 0 255

In the code above, we assigned hex variable and used nested array destructuring to assign to the red, green and blue variables.

Rest Items

Sometimes you may want to assign some items to variables, while ensuring that the remaining items are captured(assigned to another local variable). The new rest parameter syntax(...param) added in ES6 can be used with destructuring to achieve this. Here is a quick example.

const rainbow = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet'];

// Assign the first and third items to red and yellow
// Assign the remaining items to otherColors variable using the spread operator(...)
const [red,, yellow, ...otherColors] = rainbow;

console.log(otherColors); // ['green', 'blue', 'indigo', 'violet']

Here you can see that after we assigned the first and third items of the rainbow array to red and yellow respectively, we used the rest parameters syntax(...param) to capture and assign the remaining values to the otherColors variable. This is referred to as the rest items variable. Note however that the rest parameter, if used, must always appear as the last item in the destructuring array literal otherwise an error will be thrown.

There are some nice applications of rest items that are worth considering. One of which is cloning arrays.

Cloning Arrays

In JavaScript, arrays are reference types and hence they are assigned by reference instead of being copied. So in the following snippet, both the rainbow and the rainbowClone variables point to the same array reference in memory and hence any change made to rainbow is also applied to rainbowClone and vice-versa.

const rainbow = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet'];
const rainbowClone = rainbow;

// Both rainbow and rainbowClone point to the same
// array reference in memory, hence it logs (true)
console.log(rainbow === rainbowClone); // true

// Keep only the first 3 items and discard the rest
rainbowClone.splice(3);

// The change on rainbowClone also affected rainbow
console.log(rainbow); // ['red', 'orange', 'yellow']
console.log(rainbowClone); // ['red', 'orange', 'yellow']

The following code snippet shows how we can clone an array in the old-fashioned(ES5) way — Array.prototype.slice and Array.prototype.concat to the rescue.

const rainbow = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet'];

// Cloning with Array.prototype.slice
const rainbowClone1 = rainbow.slice();

console.log(rainbow === rainbowClone1); // false
console.log(rainbowClone1); // ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet']

// Cloning with Array.prototype.concat
const rainbowClone2 = rainbow.concat();

console.log(rainbow === rainbowClone2); // false
console.log(rainbowClone2); // ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet']

Here is how you can use array destructuring and the rest parameter syntax to create an array clone.

const rainbow = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet'];

// Cloning with array destructuring and spread operator
const [...rainbowClone] = rainbow;

console.log(rainbow === rainbowClone); // false
console.log(rainbowClone); // ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet']

Mixed Destructuring

There are cases when you are working with a pretty complex object/array structure and you need to assign some values from it to local variables. A good example would be an object with several deeply nested objects and arrays. In cases like this, you can use a combination of object destructuring and array destructuring to target certain parts of the complex structure as required. The following code shows a simple example.

const person = {
    name: 'John Doe',
    age: 25,
    location: {
        country: 'Canada',
        city: 'Vancouver',
        coordinates: [49.2827, -123.1207]
    }
}

// Observe how mix of object and array destructuring is being used here
// We are assigning 5 variables: name, country, city, lat, lng
const {name, location: {country, city, coordinates: [lat, lng]}} = person;

console.log(`I am ${name} from ${city}, ${country}. Latitude(${lat}), Longitude(${lng})`);

// I am John Doe from Vancouver, Canada. Latitude(49.2827), Longitude(-123.1207)

Destructured Function Parameters

Destructuring can also be applied on function parameters to extract values and assign them to local variables. Note however that the destructured parameter cannot be omitted (it is required) otherwise it throws an error. A good use case is the displaySummary() function from our initial example that expects a student object as parameter. We can destructure the student object and assign the extracted values to local variables of the function. Here is the example again:

const student = {
    name: 'John Doe',
    age: 16,
    scores: {
        maths: 74,
        english: 63,
        science: 85
    }
};

// Without Destructuring
function displaySummary(student) {
    console.log('Hello, ' + student.name);
    console.log('Your Maths score is ' + (student.scores.maths || 0));
    console.log('Your English score is ' + (student.scores.english || 0));
    console.log('Your Science score is ' + (student.scores.science || 0));
}

// With Destructuring
function displaySummary({name, scores: { maths = 0, english = 0, science = 0 }}) {
    console.log('Hello, ' + name);
    console.log('Your Maths score is ' + maths);
    console.log('Your English score is ' + english);
    console.log('Your Science score is ' + science);
}

displaySummary(student);

Here we extracted the values we need from the student object parameter and assigned them to local variables: name, maths, english and science. Notice that although we have specified default values for some of the variables, if you call the function with no arguments you will get an error because destructured parameters are always required. You can assign a fallback object literal as default value for the student object and the nested scores object in case they are not supplied to avoid the error as shown in the following snippet.

function displaySummary({ name, scores: { maths = 0, english = 0, science = 0 } = {} } = {}) {
    console.log('Hello, ' + name);
    console.log('Your Maths score is ' + maths);
    console.log('Your English score is ' + english);
    console.log('Your Science score is ' + science);
}

// Calling without a student argument
displaySummary();

// Hello, undefined
// Your Maths score is 0
// Your English score is 0
// Your Science score is 0

Conclusion

In this tutorial, we have explored the ES6 destructuring syntax and various ways we can utilize it in our code. If you are already pretty familiar with JavaScript destructuring, you may have learnt a few new stuffs as well. Although we used the rest parameter syntax at several points, it is worth noting that there is still more you can achieve with rest parameters. You can check Spread Syntax and Rest Parameters for more details.

#javascript #es6 #web-development

What is GEEK

Buddha Community

Let’s Explore ES6 Destructuring in JavaScript
Lina  Biyinzika

Lina Biyinzika

1678051620

A Practical Guide of Unsupervised Learning Algorithms

In this article, learn about Machine Learning Tutorial: A Practical  Guide of Unsupervised Learning Algorithms. Machine learning is a fast-growing technology that allows computers to learn from the past and predict the future. It uses numerous algorithms for building mathematical models and predicting future trends. Machine learning (ML) has widespread applications in the industry, including speech recognition, image recognition, churn prediction, email filtering, chatbot development, recommender systems, and much more.

Machine learning (ML) can be classified into three main categories; supervised, unsupervised, and reinforcement learning. In supervised learning, the model is trained on labeled data. While in unsupervised learning, unlabeled data is provided to the model to predict the outcomes. Reinforcement learning is feedback learning in which the agent collects a reward for each correct action and gets a penalty for a wrong decision. The goal of the learning agent is to get maximum reward points and deduce the error.

What is Unsupervised Learning?

In unsupervised learning, the model learns from unlabeled data without proper supervision.

Unsupervised learning uses machine learning techniques to cluster unlabeled data based on similarities and differences. The unsupervised algorithms discover hidden patterns in data without human supervision. Unsupervised learning aims to arrange the raw data into new features or groups together with similar patterns of data.

For instance, to predict the churn rate, we provide unlabeled data to our model for prediction. There is no information given that customers have churned or not. The model will analyze the data and find hidden patterns to categorize into two clusters: churned and non-churned customers.

Unsupervised Learning Approaches

Unsupervised algorithms can be used for three tasks—clustering, dimensionality reduction, and association. Below, we will highlight some commonly used clustering and association algorithms.

Clustering Techniques

Clustering, or cluster analysis, is a popular data mining technique for unsupervised learning. The clustering approach works to group non-labeled data based on similarities and differences. Unlike supervised learning, clustering algorithms discover natural groupings in data. 

A good clustering method produces high-quality clusters having high intra-class similarity (similar data within a cluster) and less intra-class similarity (cluster data is dissimilar to other clusters). 

It can be defined as the grouping of data points into various clusters containing similar data points. The same objects remain in the group that has fewer similarities with other groups. Here, we will discuss two popular clustering techniques: K-Means clustering and DBScan Clustering.

K-Means Clustering

K-Means is the simplest unsupervised technique used to solve clustering problems. It groups the unlabeled data into various clusters. The K value defines the number of clusters you need to tell the system how many to create.

K-Means is a centroid-based algorithm in which each cluster is associated with the centroid. The goal is to minimize the sum of the distances between the data points and their corresponding clusters.

It is an iterative approach that breaks down the unlabeled data into different clusters so that each data point belongs to a group with similar characteristics.

K-means clustering performs two tasks:

  1. Using an iterative process to create the best value of K.
  2. Each data point is assigned to its closest k-center. The data point that is closer to the particular k-center makes a cluster.

 

An illustration of K-means clustering. Image source

DBScan Clustering

“DBScan” stands for “Density-based spatial clustering of applications with noise.” There are three main words in DBscan: density, clustering, and noise. Therefore, this algorithm uses the notion of density-based clustering to form clusters and detect the noise.

Clusters are usually dense regions that are separated by lower density regions. Unlike the k-means algorithm, which works only on well-separated clusters, DBscan has a wider scope and can create clusters within the cluster. It discovers clusters of various shapes and sizes from a large set of data, which consists of noise and outliers.

There are two parameters in the DBScan algorithm:

minPts: The threshold, or the minimum number of points grouped together for a region considered as a dense region.

eps(ε): The distance measure used to locate the points in the neighborhood. 

dbscan-clustering

 

An illustration of density-based clustering. Image Source 

Association Rule Mining

An association rule mining is a popular data mining technique. It finds interesting correlations in large numbers of data items. This rule shows how frequently items occur in a transaction.

Market Basket Analysis is a typical example of an association rule mining that finds relationships between items in the grocery store. It enables retailers to identify and analyze the associations between items that people frequently buy.

Important terminology used in association rules:

Support: It tells us about the combination of items bought frequently or frequently bought items.

Confidence: It tells us how often the items A and B occur together, given the number of times A occurs.

Lift: The lift indicates the strength of a rule over the random occurrence of A and B. For instance, A->B, the life value is 5. It means that if you buy A, the occurrence of buying B is five times.

The Apriori algorithm is a well-known association rule based technique.

Apriori algorithm 

The Apriori algorithm was proposed by R. Agarwal and R. Srikant in 1994 to find the frequent items in the dataset. The algorithm’s name is based on the fact that it uses prior knowledge of frequently occurring things. 

The Apriori algorithm finds frequently occurring items with minimum support. 

It consists of two steps:

  • Generation of candidate itemsets.
  • Removing items that are infrequent and don’t fulfill the criteria of minimum support.

Practical Implementation of Unsupervised Algorithms 

In this tutorial, you will learn about the implementation of various unsupervised algorithms in Python. Scikit-learn is a powerful Python library widely used for various unsupervised learning tasks. It is an open-source library that provides numerous robust algorithms, which include classification, dimensionality reduction, clustering techniques, and association rules.

Let’s begin!

1. K-Means algorithm 

Now let’s dive deep into the implementation of the K-Means algorithm in Python. We’ll break down each code snippet so that you can understand it easily.

Import libraries

First of all, we will import the required libraries and get access to the functions.

#Let's import the required libraries
import numpy as np
import pandas as pd 
import matplotlib.pyplot as plt
import seaborn as sns

Loading the dataset 

The dataset is taken from the kaggle website. You can easily download it from the given link. To load the dataset, we use the pd.read_csv() function. head() returns the first five rows of the dataset.

my_data = pd.read_csv('Customers_Mall.csv.') my_data.head() dataset-columns

The dataset contains five columns: customer ID, gender, age, annual income in (K$), and spending score from 1-100. 

Data Preprocessing 

The info() function is used to get quick information about the dataset. It shows the number of entries, columns, total non-null values, memory usage, and datatypes. 

my_data.info()

dataset-description

 

To check the missing values in the dataset, we use isnull().sum(), which returns the total number of null values.

 

#Check missing values 
my_data.isnull().sum()

dataset-null-values

 

The box plot or whisker plot is used to detect outliers in the dataset. It also shows a statistical five number summary, which includes the minimum, first quartile, median (2nd quartile), third quartile, and maximum.

my_data.boxplot(figsize=(8,4)) dataset-boxplot-detect-outliers

Using Box Plot, we’ve detected an outlier in the annual income column. Now we will try to remove it before training our model. 

#let's remove outlier from data
med =61
my_data["Annual Income (k$)"] = np.where(my_data["Annual Income (k$)"] >
 120,med,my_data['Annual Income (k$)'])


The outlier in the annual income column has been removed now to confirm we used the box plot again.

my_data.boxplot(figsize=(8,5)) outlier-removed

Data Visualization

A histogram is used to illustrate the important features of the distribution of data. The hist() function is used to show the distribution of data in each numerical column.

my_data.hist(figsize=(6,6)) 

The correlation heatmap is used to find the potential relationships between variables in the data and to display the strength of those relationships. To display the heatmap, we have used the seaborn plotting library.

plt.figure(figsize=(10,6)) sns.heatmap(my_data.corr(), annot=True, cmap='icefire').set_title('seaborn') plt.show() dataset-histogram

Choosing the Best K Value

The iloc() function is used to select a particular cell of the data. It enables us to select a value that belongs to a specific row or column. Here, we’ve chosen the annual income and spending score columns.

 

X_val = my_data.iloc[:, 3:].values X_val

 

# Loading Kmeans Library

from sklearn.cluster import KMeans

Now we will select the best value for K using the Elbow’s method. It is used to determine the optimal number of clusters in K-means clustering.

my_val = []

for i in range(1,11):

    kmeans = KMeans(n_clusters = i, init='k-means++', random_state = 123)

    kmeans.fit(X_val)

    my_val.append(kmeans.inertia_)

The sklearn.cluster.KMeans() is used to choose the number of clusters along with the initialization of other parameters. To display the result, just call the variable.

my_val dataset-iloc-function #Visualization of clusters using elbow’s method plt.plot(range(1,11),my_val) plt.xlabel('The No of clusters') plt.ylabel('Outcome') plt.title('The Elbow Method') plt.show() clusters-elbow-method

Through Elbow’s Method, when the graph looks like an arm, then the elbow on the arm is the best value of K. In this case, we’ve taken K=3, which is the optimal value for K.

kmeans = KMeans(n_clusters = 3, init='k-means++') kmeans.fit(X_val) number-of-clusters #To show centroids of clusters  kmeans.cluster_centers_ cluster-centers #Prediction of K-Means clustering  y_kmeans = kmeans.fit_predict(X_val) y_kmeans

fit-predict-function-kmeans

Splitting the dataset into three clusters

The scatter graph is used to plot the classification results of our dataset into three clusters.

plt.scatter(X_val[y_kmeans == 0,0], X_val[y_kmeans == 0,1], c='red',s=100)

plt.scatter(X_val[y_kmeans == 1,0], X_val[y_kmeans == 1,1], c='green',s=100)

plt.scatter(X_val[y_kmeans == 2,0], X_val[y_kmeans == 2,1], c='orange',s=100)

plt.scatter(kmeans.cluster_centers_[:,0], kmeans.cluster_centers_[:,1], s=300, c='brown')

plt.title('K-Means Unsupervised Learning')

plt.show()


2. Apriori Algorithm

To implement the apriori algorithm, we will utilize “The Bread Basket” dataset. The dataset is available on Kaggle and you can download it from the link. This algorithm suggests products based on the user’s purchase history. Walmart has greatly utilized the algorithm to recommend relevant items to its users.

Let’s implement the Apriori algorithm in Python. 

Import libraries 

To implement the algorithm, we need to import some important libraries.

import pandas as pd

import matplotlib.pyplot as plt

import numpy as np

import seaborn as sns

Loading the dataset 

The dataset contains five columns and 20507 entries. The data_time is a prominent column and we can extract many vital insights from it.

my_data= pd.read_csv("bread basket.csv") my_data.head() bread-basket-dataset-apriori

Data Preprocessing 

Convert the data_time into an appropriate format.

my_data['date_time'] = pd.to_datetime(my_data['date_time'])

#Total No of unique customers

my_data['Transaction'].nunique()

unique-customers-apriori

Now we want to extract new columns from the data_time to extract meaningful information from the data.

#Let's extract date

my_data['date'] = my_data['date_time'].dt.date

#Let's extract time

my_data['time'] = my_data['date_time'].dt.time

#Extract month and replacing it with String

my_data['month'] = my_data['date_time'].dt.month

my_data['month'] = my_data['month'].replace((1,2,3,4,5,6,7,8,9,10,11,12), 

                                          ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug',

                                          'Sep','Oct','Nov','Dec'))

#Extract hour

my_data[‘hour’] = my_data[‘date_time’].dt.hour

# Replacing hours with text

# Replacing hours with text

hr_num = (1,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23)

hr_obj = (‘1-2′,’7-8′,’8-9′,’9-10′,’10-11′,’11-12′,’12-13′,’13-14′,’14-15’,

               ’15-16′,’16-17′,’17-18′,’18-19′,’19-20′,’20-21′,’21-22′,’22-23′,’23-24′)

my_data[‘hour’] = my_data[‘hour’].replace(hr_num, hr_obj)

# Extracting weekday and replacing it with String 

my_data[‘weekday’] = my_data[‘date_time’].dt.weekday

my_data[‘weekday’] = my_data[‘weekday’].replace((0,1,2,3,4,5,6), 

                                          (‘Mon’,’Tues’,’Wed’,’Thur’,’Fri’,’Sat’,’Sun’))

#Now drop date_time column

my_data.drop(‘date_time’, axis = 1, inplace = True)

After extracting the date, time, month, and hour columns, we dropped the data_time column.

Now to display, we simply use the head() function to see the changes in the dataset.

my_data.head()

dataset-apriori

# cleaning the item column

my_data[‘Item’] = my_data[‘Item’].str.strip()

my_data[‘Item’] = my_data[‘Item’].str.lower()

my_data.head()

clean-dataset

Data Visualization 

To display the top 10 items purchased by customers, we used a barplot() of the seaborn library. 

plt.figure(figsize=(10,5))

sns.barplot(x=my_data.Item.value_counts().head(10).index, y=my_data.Item.value_counts().head(10).values,palette='RdYlGn')

plt.xlabel('No of Items', size = 17)

plt.xticks(rotation=45)

plt.ylabel('Total Items', size = 18)

plt.title('Top 10 Items purchased', color = 'blue', size = 23)

plt.show()


From the graph, coffee is the top item purchased by the customers, followed by bread.

Now, to display the number of orders received each month, the groupby() function is used along with barplot() to visually show the results.

mon_Tran =my_data.groupby('month')['Transaction'].count().reset_index() mon_Tran.loc[:,"mon_order"] =[4,8,12,2,1,7,6,3,5,11,10,9] mon_Tran.sort_values("mon_order",inplace=True) plt.figure(figsize=(12,5)) sns.barplot(data = mon_Tran, x = "month", y = "Transaction") plt.xlabel('Months', size = 14) plt.ylabel('Monthly Orders', size = 14) plt.title('No of orders received each month', color = 'blue', size = 18) plt.show() orders-received-dataset

To show the number of orders received each day, we applied groupby() to the weekday column.

wk_Tran = my_data.groupby('weekday')['Transaction'].count().reset_index()

wk_Tran.loc[:,"wk_ord"] = [4,0,5,6,3,1,2]

wk_Tran.sort_values("wk_ord",inplace=True)

plt.figure(figsize=(11,4))

sns.barplot(data = wk_Tran, x = "weekday", y = "Transaction",palette='RdYlGn')

plt.xlabel('Week Day', size = 14)

plt.ylabel('Per day orders', size = 14)

plt.title('Orders received per day', color = 'blue', size = 18)

plt.show()


 Implementation of the Apriori Algorithm 

We import the mlxtend library to implement the association rules and count the number of items.

from mlxtend.frequent_patterns import association_rules, apriori

tran_str= my_data.groupby(['Transaction', 'Item'])['Item'].count().reset_index(name ='Count')

tran_str.head(8)

association-rule-mixtend

Now we’ll make a mxn matrix where m=transaction and n=items, and each row represents whether the item was in the transaction or not.

Mar_baskt = tran_str.pivot_table(index='Transaction', columns='Item', values='Count', aggfunc='sum').fillna(0)

Mar_baskt.head()

market-basket

We want to make a function that returns 0 and 1. 0 means that the item wasn’t present in the transaction, while 1 means the item exists.

def encode(val):

    if val<=0:

        return 0

    if val>=1:

        return 1

#Let's apply the function to the dataset

Basket=Mar_baskt.applymap(encode)

Basket.head()

basket-head

#using apriori algorithm to set min_support 0.01 means 1% freq_items = apriori(Basket, min_support = 0.01,use_colnames = True) freq_items.head()

frequent-items-apriori

Using the association_rules() function to generate the most frequent items from the dataset.

App_rule= association_rules(freq_items, metric = "lift", min_threshold = 1) App_rule.sort_values('confidence', ascending = False, inplace = True) App_rule.head() association-rules-apriori

From the above implementation, the most frequent items are coffee and toast, both having a lift value of 1.47 and a confidence value of 0.70. 

3. Principal Component Analysis 

Principal component analysis (PCA) is one of the most widely used unsupervised learning techniques. It can be used for various tasks, including dimensionality reduction, information compression, exploratory data analysis and Data de-noising.

Let’s use the PCA algorithm!

First we import the required libraries to implement this algorithm.

import numpy as np 

import pandas as pd

import matplotlib.pyplot as plt

import seaborn as sns

%matplotlib inline

from sklearn.decomposition import PCA

from sklearn.datasets import load_digits

Loading the Dataset 

To implement the PCA algorithm the load_digits dataset of Scikit-learn is used which can easily be loaded using the below command. The dataset contains images data which include 1797 entries and 64 columns.

 

#Load the dataset

my_data= load_digits()

#Creating features

X_value = my_data.data

#Creating target

#Let's check the shape of X_value

X_value.shape

 

dataset-X-shape

 

 

#Each image is 8x8 pixels therefore 64px  my_data.images[10] image-pixels #Let's display the image plt.gray()  plt.matshow(my_data.images[34])  plt.show()

image-pixels

Now let’s project data from 64 columns to 16 to show how 16 dimensions classify the data.

X_val = my_data.data 

y_val = my_data.target

my_pca = PCA(16)  

X_projection = my_pca.fit_transform(X_val)

print(X_val.shape)

print(X_projection.shape)

projection-shape

Using colormap we visualize that with only ten dimensions  we can classify the data points. Now we’ll select the optimal number of dimensions (principal components) by which data can be reduced into lower dimensions.

plt.scatter(X_projection[:, 0], X_projection[:, 1], c=y_val, edgecolor='white',

            cmap=plt.cm.get_cmap("gist_heat",12))

plt.colorbar();

x-projection

pca=PCA().fit(X_val)

plt.plot(np.cumsum(my_pca.explained_variance_ratio_))

plt.xlabel('Principal components')

plt.ylabel('Explained variance')

Based on the below graph, only 12 components are required to explain more than 80% of the variance which is still better than computing all the 64 features. Thus, we’ve reduced the large number of dimensions into 12 dimensions to avoid the dimensionality curse. pca=PCA().fit(X_val)

plt.plot(np.cumsum(pca.explained_variance_ratio_))

plt.xlabel('Principal components')

plt.ylabel('Explained variance')



#Let's visualize how it looks like

Unsupervised_pca = PCA(12)  

X_pro = Unsupervised_pca.fit_transform(X_val)

print("New Data Shape is =>",X_pro.shape)

#Let's Create a scatter plot

plt.scatter(X_pro[:, 0], X_pro[:, 1], c=y_val, edgecolor='white',

            cmap=plt.cm.get_cmap("nipy_spectral",10))

plt.colorbar();


principal-component-analysis

Wrapping Up 

beyond machine

In this machine learning tutorial, we’ve implemented the Kmeans, Apriori, and PCA algorithms. These are some of the most widely used algorithms, having numerous industrial applications and solve many real world problems. For instance, K-means clustering is used in astronomy to study stellar and galaxy spectra, solar polarization spectra, and X-ray spectra. And, Apriori is used by retail stores to optimize their product inventory. 

Dreaming of becoming a data scientist or data analyst even without a university and a college degree? Do you need the knowledge of data science and analysis for promotions in your current role?

Are you interested in securing your dream job in data science and analysis and looking for a way to get started, we can help you? With over 10 years of experience in data science and data analysis, we will teach you the rubrics, guiding you with one-on-one lessons from the fundamentals until you become a pro.

Our courses are affordable and easy to understand with numerous exercises and assignments you can learn from. At the completion of our courses, you’ll be readily equipped with technical and practical skills to take on any data science and data analysis role in companies, collaborate effectively among teams and help businesses meet and exceed their objectives by extracting actionable insights from data.

Original article sourced at: https://thedatascientist.com

#machine-learning 

Array Destructuring in JavaScript

Destructuring is a convenient way of extracting multiple values from data stored in objects and Arrays. ES6 introduced some significant improvements to the language, including the de-structuring of Objects and Arrays. Honestly speaking, these are my favorite edition in the JavaScript standard syntax.

Array destructuring

Let us take a look if we want to extract data from an array in es5.

Image for post

Here, we are doing something quite boring stuff and repeated the same thing again and again. But ES6 destructuring assignment makes it easier.

Image for post

We can also do this with the same result,

we can also declare variables before Assignment,

Image for post

Assign variables a default value:

Image for post

#destructuring #array-destructuring #javascript-destructuring #es6-destructuring #es6

Mike  Kozey

Mike Kozey

1656151740

Test_cov_console: Flutter Console Coverage Test

Flutter Console Coverage Test

This small dart tools is used to generate Flutter Coverage Test report to console

How to install

Add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dev_dependencies:
  test_cov_console: ^0.2.2

How to run

run the following command to make sure all flutter library is up-to-date

flutter pub get
Running "flutter pub get" in coverage...                            0.5s

run the following command to generate lcov.info on coverage directory

flutter test --coverage
00:02 +1: All tests passed!

run the tool to generate report from lcov.info

flutter pub run test_cov_console
---------------------------------------------|---------|---------|---------|-------------------|
File                                         |% Branch | % Funcs | % Lines | Uncovered Line #s |
---------------------------------------------|---------|---------|---------|-------------------|
lib/src/                                     |         |         |         |                   |
 print_cov.dart                              |  100.00 |  100.00 |   88.37 |...,149,205,206,207|
 print_cov_constants.dart                    |    0.00 |    0.00 |    0.00 |    no unit testing|
lib/                                         |         |         |         |                   |
 test_cov_console.dart                       |    0.00 |    0.00 |    0.00 |    no unit testing|
---------------------------------------------|---------|---------|---------|-------------------|
 All files with unit testing                 |  100.00 |  100.00 |   88.37 |                   |
---------------------------------------------|---------|---------|---------|-------------------|

Optional parameter

If not given a FILE, "coverage/lcov.info" will be used.
-f, --file=<FILE>                      The target lcov.info file to be reported
-e, --exclude=<STRING1,STRING2,...>    A list of contains string for files without unit testing
                                       to be excluded from report
-l, --line                             It will print Lines & Uncovered Lines only
                                       Branch & Functions coverage percentage will not be printed
-i, --ignore                           It will not print any file without unit testing
-m, --multi                            Report from multiple lcov.info files
-c, --csv                              Output to CSV file
-o, --output=<CSV-FILE>                Full path of output CSV file
                                       If not given, "coverage/test_cov_console.csv" will be used
-t, --total                            Print only the total coverage
                                       Note: it will ignore all other option (if any), except -m
-p, --pass=<MINIMUM>                   Print only the whether total coverage is passed MINIMUM value or not
                                       If the value >= MINIMUM, it will print PASSED, otherwise FAILED
                                       Note: it will ignore all other option (if any), except -m
-h, --help                             Show this help

example run the tool with parameters

flutter pub run test_cov_console --file=coverage/lcov.info --exclude=_constants,_mock
---------------------------------------------|---------|---------|---------|-------------------|
File                                         |% Branch | % Funcs | % Lines | Uncovered Line #s |
---------------------------------------------|---------|---------|---------|-------------------|
lib/src/                                     |         |         |         |                   |
 print_cov.dart                              |  100.00 |  100.00 |   88.37 |...,149,205,206,207|
lib/                                         |         |         |         |                   |
 test_cov_console.dart                       |    0.00 |    0.00 |    0.00 |    no unit testing|
---------------------------------------------|---------|---------|---------|-------------------|
 All files with unit testing                 |  100.00 |  100.00 |   88.37 |                   |
---------------------------------------------|---------|---------|---------|-------------------|

report for multiple lcov.info files (-m, --multi)

It support to run for multiple lcov.info files with the followings directory structures:
1. No root module
<root>/<module_a>
<root>/<module_a>/coverage/lcov.info
<root>/<module_a>/lib/src
<root>/<module_b>
<root>/<module_b>/coverage/lcov.info
<root>/<module_b>/lib/src
...
2. With root module
<root>/coverage/lcov.info
<root>/lib/src
<root>/<module_a>
<root>/<module_a>/coverage/lcov.info
<root>/<module_a>/lib/src
<root>/<module_b>
<root>/<module_b>/coverage/lcov.info
<root>/<module_b>/lib/src
...
You must run test_cov_console on <root> dir, and the report would be grouped by module, here is
the sample output for directory structure 'with root module':
flutter pub run test_cov_console --file=coverage/lcov.info --exclude=_constants,_mock --multi
---------------------------------------------|---------|---------|---------|-------------------|
File                                         |% Branch | % Funcs | % Lines | Uncovered Line #s |
---------------------------------------------|---------|---------|---------|-------------------|
lib/src/                                     |         |         |         |                   |
 print_cov.dart                              |  100.00 |  100.00 |   88.37 |...,149,205,206,207|
lib/                                         |         |         |         |                   |
 test_cov_console.dart                       |    0.00 |    0.00 |    0.00 |    no unit testing|
---------------------------------------------|---------|---------|---------|-------------------|
 All files with unit testing                 |  100.00 |  100.00 |   88.37 |                   |
---------------------------------------------|---------|---------|---------|-------------------|
---------------------------------------------|---------|---------|---------|-------------------|
File - module_a -                            |% Branch | % Funcs | % Lines | Uncovered Line #s |
---------------------------------------------|---------|---------|---------|-------------------|
lib/src/                                     |         |         |         |                   |
 print_cov.dart                              |  100.00 |  100.00 |   88.37 |...,149,205,206,207|
lib/                                         |         |         |         |                   |
 test_cov_console.dart                       |    0.00 |    0.00 |    0.00 |    no unit testing|
---------------------------------------------|---------|---------|---------|-------------------|
 All files with unit testing                 |  100.00 |  100.00 |   88.37 |                   |
---------------------------------------------|---------|---------|---------|-------------------|
---------------------------------------------|---------|---------|---------|-------------------|
File - module_b -                            |% Branch | % Funcs | % Lines | Uncovered Line #s |
---------------------------------------------|---------|---------|---------|-------------------|
lib/src/                                     |         |         |         |                   |
 print_cov.dart                              |  100.00 |  100.00 |   88.37 |...,149,205,206,207|
lib/                                         |         |         |         |                   |
 test_cov_console.dart                       |    0.00 |    0.00 |    0.00 |    no unit testing|
---------------------------------------------|---------|---------|---------|-------------------|
 All files with unit testing                 |  100.00 |  100.00 |   88.37 |                   |
---------------------------------------------|---------|---------|---------|-------------------|

Output to CSV file (-c, --csv, -o, --output)

flutter pub run test_cov_console -c --output=coverage/test_coverage.csv

#### sample CSV output file:
File,% Branch,% Funcs,% Lines,Uncovered Line #s
lib/,,,,
test_cov_console.dart,0.00,0.00,0.00,no unit testing
lib/src/,,,,
parser.dart,100.00,100.00,97.22,"97"
parser_constants.dart,100.00,100.00,100.00,""
print_cov.dart,100.00,100.00,82.91,"29,49,51,52,171,174,177,180,183,184,185,186,187,188,279,324,325,387,388,389,390,391,392,393,394,395,398"
print_cov_constants.dart,0.00,0.00,0.00,no unit testing
All files with unit testing,100.00,100.00,86.07,""

Installing

Use this package as an executable

Install it

You can install the package from the command line:

dart pub global activate test_cov_console

Use it

The package has the following executables:

$ test_cov_console

Use this package as a library

Depend on it

Run this command:

With Dart:

 $ dart pub add test_cov_console

With Flutter:

 $ flutter pub add test_cov_console

This will add a line like this to your package's pubspec.yaml (and run an implicit dart pub get):

dependencies:
  test_cov_console: ^0.2.2

Alternatively, your editor might support dart pub get or flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:test_cov_console/test_cov_console.dart';

example/lib/main.dart

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or simply save your changes to "hot reload" in a Flutter IDE).
        // Notice that the counter didn't reset back to zero; the application
        // is not restarted.
        primarySwatch: Colors.blue,
        // This makes the visual density adapt to the platform that you run
        // the app on. For desktop platforms, the controls will be smaller and
        // closer together (more dense) than on mobile platforms.
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required this.title}) : super(key: key);

  // This widget is the home page of your application. It is stateful, meaning
  // that it has a State object (defined below) that contains fields that affect
  // how it looks.

  // This class is the configuration for the state. It holds the values (in this
  // case the title) provided by the parent (in this case the App widget) and
  // used by the build method of the State. Fields in a Widget subclass are
  // always marked "final".

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      // This call to setState tells the Flutter framework that something has
      // changed in this State, which causes it to rerun the build method below
      // so that the display can reflect the updated values. If we changed
      // _counter without calling setState(), then the build method would not be
      // called again, and so nothing would appear to happen.
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    // This method is rerun every time setState is called, for instance as done
    // by the _incrementCounter method above.
    //
    // The Flutter framework has been optimized to make rerunning build methods
    // fast, so that you can just rebuild anything that needs updating rather
    // than having to individually change instances of widgets.
    return Scaffold(
      appBar: AppBar(
        // Here we take the value from the MyHomePage object that was created by
        // the App.build method, and use it to set our appbar title.
        title: Text(widget.title),
      ),
      body: Center(
        // Center is a layout widget. It takes a single child and positions it
        // in the middle of the parent.
        child: Column(
          // Column is also a layout widget. It takes a list of children and
          // arranges them vertically. By default, it sizes itself to fit its
          // children horizontally, and tries to be as tall as its parent.
          //
          // Invoke "debug painting" (press "p" in the console, choose the
          // "Toggle Debug Paint" action from the Flutter Inspector in Android
          // Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
          // to see the wireframe for each widget.
          //
          // Column has various properties to control how it sizes itself and
          // how it positions its children. Here we use mainAxisAlignment to
          // center the children vertically; the main axis here is the vertical
          // axis because Columns are vertical (the cross axis would be
          // horizontal).
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

Author: DigitalKatalis
Source Code: https://github.com/DigitalKatalis/test_cov_console 
License: BSD-3-Clause license

#flutter #dart #test 

Let’s Explore ES6 Destructuring in JavaScript

JavaScript is currently one of the most used programming languages in the world, being used across different platforms ranging from web browsers, mobile devices, VR, web servers, etc. Although the language has not changed a lot through the years when compared to other programming languages, there are some recent changes that are worth taking note of, because of the expressive power they add to the language — some of which are: template literals, destructuring, spread operator, arrow functions, classes, etc.

In this tutorial, our major focus will be on learning how to harness the power of destructuring to simplify our JavaScript programs. Before we dive into the what and how of destructuring I think the why should be considered. If you already use TypeScript or a modern JavaScript framework like React, Vue, Preact, Angular, etc, you may already be familiar with destructuring. However, there is a possibility that by going through this tutorial, you may learn a few new stuffs about destructuring you may not have known.

For this tutorial, it is assumed you already have some prior experience writing JavaScript code. There is a chance that some of the code snippets may not work on your browser depending on the version of the browser, since all the ES6 and ES7 features are not yet fully supported in all browsers. You may opt to test the code snippets on Codepen or your favorite online JavaScript live editor. Another alternative would be using the Babel transpiler to get it to work on your browser.

Why Destructuring?

To explain the why of destructuring, we will consider a scenario which most of us might be familiar with or might have come across at one time or the other when coding in JavaScript. Imagine we have the data of a student including scores in three subjects(Maths, Elementary Science, English) represented in an object and we need to display some information based on this data. We could end up with something that looks like this:

const student = {
    name: 'John Doe',
    age: 16,
    scores: {
        maths: 74,
        english: 63,
        science: 85
    }
};

function displaySummary(student) {
    console.log('Hello, ' + student.name);
    console.log('Your Maths score is ' + (student.scores.maths || 0));
    console.log('Your English score is ' + (student.scores.english || 0));
    console.log('Your Science score is ' + (student.scores.science || 0));
}

displaySummary(student);

// Hello, John Doe
// Your Maths score is 74
// Your English score is 63
// Your Science score is 85

With the above code snippet, we would achieve the desired result. However, there are a few caveats to writing code this way. One of which is — you can easily make a typo and instead of writing scores.english for example, you write score.english which will result in an error. Again, if the scores object we are accessing is deeply nested in another object, the object access chain becomes longer which could mean more typing. These may not seem to be much an issue, but with destructuring we can do the same in a more expressive and compact syntax.

What is Destructuring?

Destructuring simply implies breaking down a complex structure into simpler parts. In JavaScript, this complex structure is usually an object or an array. With the destructuring syntax, you can extract smaller fragments from arrays and objects. Destructuring syntax can be used for variable declaration or variable assignment. You can also handle nested structures by using nested destructuring syntax.

Using destructuring, the function from our previous snippet will look like this:

function displaySummary({ name, scores: { maths = 0, english = 0, science = 0 } }) {
    console.log('Hello, ' + name);
    console.log('Your Maths score is ' + maths);
    console.log('Your English score is ' + english);
    console.log('Your Science score is ' + science);
}

There is a chance that the code in the last snippet didn’t go down well with you. If that’s the case, then follow up with the tutorial till you get to the end — I assure you it will all make sense. Let’s continue to learn how we can harness the power of destructuring.

Object Destructuring

What we saw in that last snippet is a form of object destructuring being used as an assignment to a function. Let’s explore what we can do with object destructuring starting from the ground up. Basically, you use an object literal on the left-hand-side of an assignment expression for object destructuring. Here is a basic snippet:

const student = {
    firstname: 'Glad',
    lastname: 'Chinda',
    country: 'Nigeria'
};

// Object Destructuring
const { firstname, lastname, country } = student;

console.log(firstname, lastname, country); // Glad Chinda Nigeria

Here we used object destructuring syntax to assign values to three variables: firstname, lastname and country using the values from their corresponding keys on the student object. This is the most basic form of object destructuring.

The same syntax can be used in variable assignment as follows:

// Initialize local variables
let country = 'Canada';
let firstname = 'John';
let lastname = 'Doe';

const student = {
    firstname: 'Glad',
    lastname: 'Chinda',
    country: 'Nigeria'
};

// Reassign firstname and lastname using destructuring
// Enclose in a pair of parentheses, since this is an assignment expression
({ firstname, lastname } = student);

// country remains unchanged (Canada)
console.log(firstname, lastname, country); // Glad Chinda Canada

The above snippet shows how to use object destructuring to assign new values to local variables. Notice that we had to use a pair of enclosing parentheses (**()**) in the assignment expression. If omitted, the destructuring object literal will be taken to be a block statement, which will lead to an error because a block cannot appear at the left-hand-side of an assignment expression.

Default Values

Trying to assign a variable corresponding to a key that does not exist on the destructured object will cause the value undefined to be assigned instead. You can pass default values that will be assigned to such variables instead of undefined. Here is a simple example.

const person = {
    name: 'John Doe',
    country: 'Canada'
};

// Assign default value of 25 to age if undefined
const { name, country, age = 25 } = person;

// Here I am using ES6 template literals
console.log(`I am ${name} from ${country} and I am ${age} years old.`);

// I am John Doe from Canada and I am 25 years old.'

Here we assigned a default value of 25 to the age variable. Since the age key does not exist on the person object, 25 is assigned to the age variable instead of undefined.

Using Different Variable Names

So far, we have been assigning to variables that have the same name as the corresponding object key. You can assign to a different variable name using this syntax: **[object_key]:[variable_name]**. You can also pass default values using the syntax: **[object_key]:[variable_name] = [default_value]**. Here is a simple example.

const person = {
    name: 'John Doe',
    country: 'Canada'
};

// Assign default value of 25 to years if age key is undefined
const { name: fullname, country: place, age: years = 25 } = person;

// Here I am using ES6 template literals
console.log(`I am ${fullname} from ${place} and I am ${years} years old.`);

// I am John Doe from Canada and I am 25 years old.'

Here we created three local variables namely: fullname, place and years that map to the name, country and age keys respectively of the person object. Notice that we specified a default value of 25 for the years variable in case the age key is missing on the person object.

Nested Object Destructuring

Referring back to our initial destructuring example, we recall that the scores object is nested in the student object. Let’s say we want to assign the Maths and Science scores to local variables. The following code snippet shows how we can use nested object destructuring to do this.

const student = {
    name: 'John Doe',
    age: 16,
    scores: {
        maths: 74,
        english: 63
    }
};

// We define 3 local variables: name, maths, science
const { name, scores: {maths, science = 50} } = student;

console.log(`${name} scored ${maths} in Maths and ${science} in Elementary Science.`);

// John Doe scored 74 in Maths and 50 in Elementary Science.

Here, we defined three local variables: name, maths and science. Also, we specified a default value of 50 for science in case it does not exist in the nested scores object. Notice that, scores is not defined as a variable. Instead, we use nested destructuring to extract the maths and science values from the nestedscores object.

When using nested object destructuring, be careful to avoid using an empty nested object literal. Though it is valid syntax, it actually does no assignment. For example, the following destructuring does absolutely no assignment.

// This does no assignment
// Because of the empty nested object literal ({})
const { scores: {} } = student;

Array Destructuring

By now you are already feeling like a destructuring ninja, having gone through the rigours of understanding object destructuring. The good news is that array destructuring is very much similar and straight forward so let’s dive in right away.

In array destructuring, you use an array literal on the left-hand-side of an assignment expression. Each variable name on the array literal maps to the corresponding item at the same index on the destructured array. Here is a quick example.

const rgb = [255, 200, 0];

// Array Destructuring
const [red, green, blue] = rgb;

console.log(`R: ${red}, G: ${green}, B: ${blue}`); // R: 255, G: 200, B: 0

In this example, we have assigned the items in the rgb array to three local variables: red, green and blue using array destructuring. Notice that each variable is mapped to the corresponding item at the same index on the rgb array.

Default Values

If the number of items in the array is more than the number of local variables passed to the destructuring array literal, then the excess items are not mapped. But if the number of local variables passed to the destructuring array literal exceed the number of items in the array, then each excess local variable will be assigned a value of undefined except you specify a default value.

Just as with object destructuring, you can set default values for local variables using array destructuring. In the following example, we would set default values for some variables in case a corresponding item is not found.

const rgb = [200];

// Assign default values of 255 to red and blue
const [red = 255, green, blue = 255] = rgb;

console.log(`R: ${red}, G: ${green}, B: ${blue}`); // R: 200, G: undefined, B: 255

You can also do an array destructuring assignment. Unlike with object destructuring, you don’t need to enclose the assignment expression in parentheses. Here is an example.

let red = 100;
let green = 200;
let blue = 50;

const rgb = [200, 255, 100];

// Destructuring assignment to red and green
[red, green] = rgb;

console.log(`R: ${red}, G: ${green}, B: ${blue}`); // R: 200, G: 255, B: 50

Skipping Items

It is possible to skip some items you don’t want to assign to local variables and only assign the ones you are interested in. Here is an example of how we can assign only the blue value to a local variable.

const rgb = [200, 255, 100];

// Skip the first two items
// Assign the only third item to the blue variable
const [,, blue] = rgb;

console.log(`Blue: ${blue}`); // Blue: 100

We used comma separation(,) to omit the first two items of the rgb array, since we only needed the third item.

Swapping Variables

One very nice application of array destructuring is in swapping local variables. Imagine you are building a photo manipulation app and you want to be able to swap the height and width dimensions of a photo when the orientation of the photo is switched between landscape and portrait. The old-fashioned way of doing this will look like the following.

let width = 300;
let height = 400;
const landscape = true;

console.log(`${width} x ${height}`); // 300 x 400

if (landscape) {
    // An extra variable needed to copy initial width
    let initialWidth = width;

    // Swap the variables
    width = height;
  
    // height is assigned the copied width value
    height = initialWidth;

    console.log(`${width} x ${height}`); // 400 x 300
}

The above code snippet performs the task, although we had to use an additional variable to copy the value of one of the swapped variables. With array destructuring, we can perform the swap with a single assignment statement. The following snippet shows how array destructuring can be used to achieve this.

let width = 300;
let height = 400;
const landscape = true;

console.log(`${width} x ${height}`); // 300 x 400

if (landscape) {
    // Swap the variables
    [width, height] = [height, width];
  
    console.log(`${width} x ${height}`); // 400 x 300
}

Nested Array Destructuring

Just as with objects, you can also do nested destructuring with arrays. The corresponding item must be an array in order to use a nested destructuring array literal to assign items in it to local variables. Here is a quick example to illustrate this.

const color = ['#FF00FF', [255, 0, 255], 'rgb(255, 0, 255)'];

// Use nested destructuring to assign red, green and blue
const [hex, [red, green, blue]] = color;

console.log(hex, red, green, blue); // #FF00FF 255 0 255

In the code above, we assigned hex variable and used nested array destructuring to assign to the red, green and blue variables.

Rest Items

Sometimes you may want to assign some items to variables, while ensuring that the remaining items are captured(assigned to another local variable). The new rest parameter syntax(...param) added in ES6 can be used with destructuring to achieve this. Here is a quick example.

const rainbow = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet'];

// Assign the first and third items to red and yellow
// Assign the remaining items to otherColors variable using the spread operator(...)
const [red,, yellow, ...otherColors] = rainbow;

console.log(otherColors); // ['green', 'blue', 'indigo', 'violet']

Here you can see that after we assigned the first and third items of the rainbow array to red and yellow respectively, we used the rest parameters syntax(...param) to capture and assign the remaining values to the otherColors variable. This is referred to as the rest items variable. Note however that the rest parameter, if used, must always appear as the last item in the destructuring array literal otherwise an error will be thrown.

There are some nice applications of rest items that are worth considering. One of which is cloning arrays.

Cloning Arrays

In JavaScript, arrays are reference types and hence they are assigned by reference instead of being copied. So in the following snippet, both the rainbow and the rainbowClone variables point to the same array reference in memory and hence any change made to rainbow is also applied to rainbowClone and vice-versa.

const rainbow = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet'];
const rainbowClone = rainbow;

// Both rainbow and rainbowClone point to the same
// array reference in memory, hence it logs (true)
console.log(rainbow === rainbowClone); // true

// Keep only the first 3 items and discard the rest
rainbowClone.splice(3);

// The change on rainbowClone also affected rainbow
console.log(rainbow); // ['red', 'orange', 'yellow']
console.log(rainbowClone); // ['red', 'orange', 'yellow']

The following code snippet shows how we can clone an array in the old-fashioned(ES5) way — Array.prototype.slice and Array.prototype.concat to the rescue.

const rainbow = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet'];

// Cloning with Array.prototype.slice
const rainbowClone1 = rainbow.slice();

console.log(rainbow === rainbowClone1); // false
console.log(rainbowClone1); // ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet']

// Cloning with Array.prototype.concat
const rainbowClone2 = rainbow.concat();

console.log(rainbow === rainbowClone2); // false
console.log(rainbowClone2); // ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet']

Here is how you can use array destructuring and the rest parameter syntax to create an array clone.

const rainbow = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet'];

// Cloning with array destructuring and spread operator
const [...rainbowClone] = rainbow;

console.log(rainbow === rainbowClone); // false
console.log(rainbowClone); // ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet']

Mixed Destructuring

There are cases when you are working with a pretty complex object/array structure and you need to assign some values from it to local variables. A good example would be an object with several deeply nested objects and arrays. In cases like this, you can use a combination of object destructuring and array destructuring to target certain parts of the complex structure as required. The following code shows a simple example.

const person = {
    name: 'John Doe',
    age: 25,
    location: {
        country: 'Canada',
        city: 'Vancouver',
        coordinates: [49.2827, -123.1207]
    }
}

// Observe how mix of object and array destructuring is being used here
// We are assigning 5 variables: name, country, city, lat, lng
const {name, location: {country, city, coordinates: [lat, lng]}} = person;

console.log(`I am ${name} from ${city}, ${country}. Latitude(${lat}), Longitude(${lng})`);

// I am John Doe from Vancouver, Canada. Latitude(49.2827), Longitude(-123.1207)

Destructured Function Parameters

Destructuring can also be applied on function parameters to extract values and assign them to local variables. Note however that the destructured parameter cannot be omitted (it is required) otherwise it throws an error. A good use case is the displaySummary() function from our initial example that expects a student object as parameter. We can destructure the student object and assign the extracted values to local variables of the function. Here is the example again:

const student = {
    name: 'John Doe',
    age: 16,
    scores: {
        maths: 74,
        english: 63,
        science: 85
    }
};

// Without Destructuring
function displaySummary(student) {
    console.log('Hello, ' + student.name);
    console.log('Your Maths score is ' + (student.scores.maths || 0));
    console.log('Your English score is ' + (student.scores.english || 0));
    console.log('Your Science score is ' + (student.scores.science || 0));
}

// With Destructuring
function displaySummary({name, scores: { maths = 0, english = 0, science = 0 }}) {
    console.log('Hello, ' + name);
    console.log('Your Maths score is ' + maths);
    console.log('Your English score is ' + english);
    console.log('Your Science score is ' + science);
}

displaySummary(student);

Here we extracted the values we need from the student object parameter and assigned them to local variables: name, maths, english and science. Notice that although we have specified default values for some of the variables, if you call the function with no arguments you will get an error because destructured parameters are always required. You can assign a fallback object literal as default value for the student object and the nested scores object in case they are not supplied to avoid the error as shown in the following snippet.

function displaySummary({ name, scores: { maths = 0, english = 0, science = 0 } = {} } = {}) {
    console.log('Hello, ' + name);
    console.log('Your Maths score is ' + maths);
    console.log('Your English score is ' + english);
    console.log('Your Science score is ' + science);
}

// Calling without a student argument
displaySummary();

// Hello, undefined
// Your Maths score is 0
// Your English score is 0
// Your Science score is 0

Conclusion

In this tutorial, we have explored the ES6 destructuring syntax and various ways we can utilize it in our code. If you are already pretty familiar with JavaScript destructuring, you may have learnt a few new stuffs as well. Although we used the rest parameter syntax at several points, it is worth noting that there is still more you can achieve with rest parameters. You can check Spread Syntax and Rest Parameters for more details.

#javascript #es6 #web-development

Rose Lancy

Rose Lancy

1594027859

What’s the difference between Var, Let and Const in JavaScript?

In the not so distant past there was only one way to define a variable in JavaScript, and that was with var. However, with the introduction of ES6 two additional ways were added, let and const. Wait…why do we need three different ways to do the same thing? Are there instances where one should be used over another? Well, those are some of the questions that I am going to answer for you in this article. But first, we need to have a little discussion about a concept called scope.

Function-scope vs Block-scope

JavaScript has two different scopes. The first is function-scope, sometimes referred to as global-scope, and the second is block-scope. Let’s look at a few examples to get a better understanding of the difference between function-scope and block-scope.

Function-scope

function someFunction() {
	var foo = 'I am foo!'
	
	console.log(foo); // This prints 'I am foo!' to the console
}

console.log(foo); // ReferenceError: foo is not defined

In the above example, the value of foo is return on line 4 within the function, but throws an error when we attempt to access foo outside of the function on line 7. This is because variables defined using var are function-scoped. They can only be accessed within the function in which they are defined. So what about block-scope?

Block-scope

Let’s add a few more variables using let and const , as well as an if statement to our previous function and see how the scope of these variables differ.

function someFunction() {
	if (true) {
		var foo = 'I am foo!';
		let bar = 'I am bar!';
		const baz = 'I am baz!;
		
		console.log(foo); // Prints 'I am foo!' to the console
		console.log(bar); // Prints 'I am bar!' to the console
		console.log(baz); // Prints 'I am baz!' to the console
	}
	
	console.log(foo); // Prints 'I am foo!' to the console
	console.log(foo); // ReferenceError: bar is not defined
	console.log(foo); // ReferenceError: baz is not defined
}

// Any console logging foo, bar or baz here will return a RefferenceError

As you can see in lines 7–9, all of the console.log() statements within the if statement return the expected variable values. However, upon inspection of lines 12–14, we begin to see some differences. On line 12, the value for foo is displayed in the console, but lines 13 and 14 return ReferenceError for bar and baz. This is because let and const are block-scoped!

#javascript #javascript-tips #javascript-scope #es6