loading...
Cover image for JavaScript30: Day 4 - Solve Real Life challenges using Array Methods

JavaScript30: Day 4 - Solve Real Life challenges using Array Methods

akdeberg profile image Anik Khan ・5 min read

I've completed the Day 4 of Wes Bos JavaScript 30.
Unlike the previous challenges, this one is solely focused on language features, no HTML/CSS. It's about using various array methods to manipulate data.

What did I solve?

Wes Bos posed some of the very interesting and real-life problems which can be solved by various array methods i.e. Array.prototype.filter(), Array.prototype.map(), Array.prototype.sort(), Array.prototype.reduce()

My Experience

To be honest, this part made me feel at home😊 Being someone who had spent more time in the backend, it comes off as less intimidating than the CSS.
Having said that, I struggled with a couple of challenges especially the last one.

The Challenge & My Learnings

Given Data:


    const inventors = [
      { first: 'Albert', last: 'Einstein', year: 1879, passed: 1955 },
      { first: 'Isaac', last: 'Newton', year: 1643, passed: 1727 },
      { first: 'Galileo', last: 'Galilei', year: 1564, passed: 1642 },
      { first: 'Marie', last: 'Curie', year: 1867, passed: 1934 },
      { first: 'Johannes', last: 'Kepler', year: 1571, passed: 1630 },
      { first: 'Nicolaus', last: 'Copernicus', year: 1473, passed: 1543 },
      { first: 'Max', last: 'Planck', year: 1858, passed: 1947 },
      { first: 'Katherine', last: 'Blodgett', year: 1898, passed: 1979 },
      { first: 'Ada', last: 'Lovelace', year: 1815, passed: 1852 },
      { first: 'Sarah E.', last: 'Goode', year: 1855, passed: 1905 },
      { first: 'Lise', last: 'Meitner', year: 1878, passed: 1968 },
      { first: 'Hanna', last: 'Hammarström', year: 1829, passed: 1909 }
    ];
  • Filter the list of inventors for those who were born in the 1500's
const earlyInventors = inventors.filter((inventor) => inventor.year >= 1500 && inventor.year < 1600)
console.table(earlyInventors)

The filter() method- goes through each array element, check them against a certain condition, returns a new array with the elements that met the condition.

  • Give us an array of the inventors first and last names
const inventorsName = inventors.map((inventor) => `${inventor.first} ${inventor.last}`)
 console.table(inventorsName)

The map() method- goes through each element, make them do a specific task, and returns a new array with the result.
Here, each inventor from the inventors array is passed to an arrow function that concatenates the first name and last names & returns an array with the results

  • How many years did all the inventors live all together?
const livingYear = inventors.reduce((acc, inventor) => acc + (inventor.passed - inventor.year), 0)
console.log(livingYear)

The reduce() method- executes a reducer function (that you provide) on each element of the array, resulting in a single output value.
When you asked to accumulate something from an array, you probably wanna use reduce() method.
The reducer function that it executes can take up to 4 arguments; but commonly we use 2 arguments- accumulator and the current value.
The accumulator is the accumulated value previously returned in the last invocation & we usually initially initialize it to 0 (as the second argument of reduce() method).
And the current value is the current item being processed.

  • Sort the inventors by years lived
const byLivingYears = inventors.sort((a, b) => {
      return (a.passed - a.year) < (b.passed - b.year) ? 1 : -1
    })
    console.table(byLivingYears)

The sort() method- when provided with a compare function(which takes 2 arguments) like here, all non-undefined array elements are sorted according to the return value of the compare function.
Return value -1 means, item comes first
Return value 1 means, item comes last
Return value 0 means, the item's position is unchanged
For example, aNumber < anotherNumber ? -1 : 1
means aNumber will comes first if it less than the anotherNumber & vice versa.

//select all the boulevards anchors form the page
    //#mw-content-text is found by inspection chrome dev tool
    const linksNode = document.querySelectorAll('#mw-content-text a')
    //convert the linksNode to array, find the text of the anchor tag & get all that includes 'de' in them
    const deBoulevard = [...linksNode].map(link => link.textContent).filter(boulevards => boulevards.includes('de'))
    console.table(deBoulevard)

To solve this we need to use multiple array methods as you can see.
First, we select the DOM element that contains all the anchor tags, using the mw-content-text id
As querySelectorAll() returns a nodeList we need to convert that to an array & then we used map() to find the text of the anchortags and then used filter() to filter by checking if they include 'de'

Now working with different data-

    const people = ['Beck, Glenn', 'Becker, Carl', 'Beckett, Samuel', 'Beddoes, Mick', 'Beecher, Henry',
      'Beethoven, Ludwig', 'Begin, Menachem', 'Belloc, Hilaire', 'Bellow, Saul', 'Benchley, Robert',
      'Benenson, Peter', 'Ben-Gurion, David', 'Benjamin, Walter', 'Benn, Tony', 'Bennington, Chester',
      'Benson, Leana', 'Bent, Silas', 'Bentsen, Lloyd', 'Berger, Ric', 'Bergman, Ingmar', 'Berio, Luciano',
      'Berle, Milton', 'Berlin, Irving', 'Berne, Eric', 'Bernhard, Sandra', 'Berra, Yogi', 'Berry, Halle',
      'Berry, Wendell', 'Bethea, Erin', 'Bevan, Aneurin', 'Bevel, Ken', 'Biden, Joseph', 'Bierce, Ambrose',
      'Biko, Steve', 'Billings, Josh', 'Biondo, Frank', 'Birrell, Augustine', 'Black, Elk', 'Blair, Robert',
      'Blair, Tony', 'Blake, William'
    ];

See all elements are string containing last and first name. They aren't structured correctly to work with. So if we need to do some operation on them we need to give them some shape based off of our challenge.

  • Sort the people alphabetically by last name

Sort the people alphabetically wouldn't be hard but as the first name and last name are packed in one single string, we need to find a way to split them. and do the operation accordingly.

    const peopleByLastName = people.sort((a, b) => {
      //The split() method divides a String into an ordered list of substrings
      const [aLast, aFirst] = a.split(',')
      //const [aLast, aFirst] is called restructuring 
      //which makes it possible to unpack values from arrays, or properties from objects, into distinct variables.
      const [bLast, bFirst] = b.split(',')
      return aLast > bLast ? 1 : -1 //in ascending order. smaller letter like 'a' comes first
    })
    console.log(peopleByLastName)

  • Sum up the frequency of each of these-
 const data = ['car', 'car', 'truck', 'truck', 'bike', 'walk', 'car', 'van', 'bike', 'walk', 'car', 'van', 'car',
      'truck'
    ];

This one is a bit tricky for me to solve. But the idea was pretty simple. The concept is each array item will be the object's key and its number of appearances will be it's key. For example, {car: 5, truck: 2}

  1. create an empty object
  2. loop through each array item; when a new item is found assigned it's value to 1 and if the item is existed previously increase it's value.
   const data = ['car', 'car', 'truck', 'truck', 'bike', 'walk', 'car', 'van', 'bike', 'walk', 'car', 'van', 'car',
      'truck'
    ];
    const vehicle = data.reduce(function (obj, item) {
      if (!obj.item) { //checks if the item is new
        obj.item = 0 //assign 0 for the new item
      }
      obj.item++ //icrement the value
      return obj
    }, {})

GitHub:

View on GitHub

Posted on by:

akdeberg profile

Anik Khan

@akdeberg

Convincing computers to do human tasks

Discussion

pic
Editor guide
 

I think this has a typo

 if (!obj.item) { //checks if the item is new

and should be generally obj[item].

But it might be a bit nicer like this:

const histogram = (map, key) => map.set(key, (map.get(key) || 0) + 1);

data.reduce(histogram, new Map())
 

Hey many many thanks for the suggestion.😊 I hope many would find this helpful 💗