Skip to main content

Command Palette

Search for a command to run...

JS - Loops and Higher Order function

Updated
11 min readView as Markdown
JS - Loops and Higher Order function

loops are helpful when we want to execute the same code a lot of times.

for loop

Here below is a example of printing 1 to 10

for(let i = 1; i <= 5; i++){
    console.log(i)
}

Output

1
2
3
4
5

Pointers:

  • let i = 1 , simply initializing a variable called i to 1, this only happens once every loop

  • i <= 5 , condition checking if true it will execute the code inside the loop {}

  • i++ , simply incrementing I from 1 to 2, this happens after executing the code inside the loop(if condition matches) then we check the condition again if true then execute code again, then increment, .... as long as condition is true, finally i becomes 6 which is not less than or equal to 5 and we break out of the loop.

  • If you make a loop where at no point the condition is false it creates a infinite loop, and will run infinitely.

Nested loops

printing the pattern

*
**
***
****
*****

Code:

for(let i=1; i<=5; i++){
    for(let j=1; j<=i; j++){
        process.stdout.write('*')
    }
    console.log()
}

Pointer:

  • Outer loop runs for 5 times and each time inner loop runs i number of times, first 1 then 2 then 3...hence it prints * in that order

  • process.stdout.write() only works on node not browser console, you can use it to print on console without sending the next output to next line.

  • inner loop can access outer loops variable ( i ) due to scope but outer loop cannot access inner loops variables (variables created inside inner loop like j)

Printing Array elements

let superHeroes = ["wonder woman", "she hulk", "robin", "dare devil"]

for(let i=0; i<superHeroes.length; i++){
    console.log(superHeroes[i])
}

Output

wonder woman
she hulk
robin
dare devil

Pointer : If you go out of max array length it won't throw error but return undefined elements.

break and continue

for(let i=1; i<=5; i++){
    if(i === 3){
        break;
    }
    console.log(i)
}
console.log('--OUT OF LOOP--')

Output

1
2
--OUT OF LOOP--

As soon as i === 3 condition was true break was triggered and we went out of the loop terminating it.

for(let i=1; i<=5; i++){
    if(i === 3){
        continue;
    }
    console.log(i)
}
console.log('--OUT OF LOOP--')

Output

1
2
4
5
--OUT OF LOOP--

continue simply doesn't execute the code in that iteration after it, goes to next iteration.

Note: In case of nested loops, break and continue work on the inner most loop only where it is written and doesn't affect the other ones.

while and do while

let's copy the same for loop we used in the first example of printing 1 to 5

for(let i = 1; i <= 5; i++){
    console.log(i)
}

while loop is a different way of creating the loop, where only conditional part is necessary.

let i = 1
while(i <= 5){
    console.log(i)
    i = i+1
}

Now let's write the same logic in do while loop.

let i = 1

do {
    console.log(i)
    i = i+1
} while(i <= 5);

Pointers:

  • One advantage of for loop is i stays inside the loop's scope

  • control flow for for and while is the same declaration -> condition check -> execute code inside loop -> increment/decrement -> execute code ->.....until condition is false. do while is a bit different, for do while we have declaration -> execute code inside loop -> increment/decrement -> condition check -> execute code.......

Hence for i starting with 6 others will return nothing as it won't satisfy i <= 5 condition and we will never execute the code within loop, for do while we first print 6, then after when condition doesn't satisfy we go out of the loop.

High order Array & Object loops

Iterating Array with for of loop

const arr = [1, 2, 3, 4, 5]

for (const element of arr) {
    console.log(element)
}

Output

1
2
3
4
5

Iterating String with for of loop

const word = 'hello'

for (const letter of word) {
    console.log(letter)
}

Output

h
e
l
l
o

Iterating Map with for of loop

Maps are very similar to Objects, they have key value pairs as well but remembers order the keys were inserted, has unique keys (if you wanna insert duplicate keys it will silently fail)

Use [map name].set() method to insert key value pairs.

const ourMap = new Map()

ourMap.set('IN', 'India')
ourMap.set('USA', 'United States of America')
ourMap.set('Fr', 'France')

console.log(ourMap)

Output

Map(3) {
  'IN' => 'India',
  'USA' => 'United States of America',
  'Fr' => 'France'
}

Now lets try and apply for of loop

for (const element of ourMap) {
    console.log(element)
}

Output

[ 'IN', 'India' ]
[ 'USA', 'United States of America' ]
[ 'Fr', 'France' ]

So it returns each element of the map grouped as an array now to separate them we can use element[0] and element[1] or use a different syntax in the for of loop itself.

for (const [key, value] of ourMap) {
    console.log(key,'is',value)
}

Output

IN is India
USA is United States of America
Fr is France

This is how we can restructure the array element.

Iterating Object with for of loop (doesn't work)

Yes for of loops don't work on Objects....

Iterating Object with for in loop

for in loop actually returns the key only.

const programmingLanguages = {
    js: 'javascript',
    cpp: 'c++',
    py: 'Python',
    swift: 'swift by apple'
}

for (const key in programmingLanguages) {
    console.log(key, '->', programmingLanguages[key])
}

Output

js -> javascript
cpp -> c++
py -> Python
swift -> swift by apple

Iterating Array with for in loop

since for in loop only returns the key not the value, in arrays that's the index 0,1,2,3,4...

const coding = ['java', 'python', 'cpp', 'js']

for (const key in coding) {
    process.stdout.write(coding[key]+' ')
}
console.log()

Output

java python cpp js 

Iterating Map with for in loop (doesn't work)

Yup maps keys aren't iterable like this, won't throw an error but will show no output.

for each loop - Arrays

A function that accepts up to three arguments(item, index and array itself). forEach calls the callback function (no name) one time for each element in the array.

for each loop always return undefined.

Performs the specified action for each element in an array.

const coding = ['java', 'python', 'cpp', 'js']

coding.forEach(function (item){
    console.log(item)
})

Output

java
python
cpp
js

we may also use arrow function.

const coding = ['java', 'python', 'cpp', 'js']

coding.forEach((item) => {
    console.log(item)
})

We can also pass a function reference and define the function separately.

const coding = ['java', 'python', 'cpp', 'js']

coding.forEach(printEachElement)

function printEachElement(item){
    console.log(item)
}

To understand Internal working of forEach, let's create a forEach function ourselves.

const coding = ['java', 'python', 'cpp', 'js']
ourForEach((item) => (console.log(item)))

function ourForEach(action){
    for(let i=0;i<coding.length;i++){
        action(coding[i])
    }
}

As you can see we had to pass a function into the ourForEach function hence it's called higher order functions.

forEach() expects a synchronous function, it doesn't wait for promises. There is no way to stop or break a forEach() loop other than throwing an exception or error.

If you want to use early termination use for, for...of and for...in.

Traversing array of objects using for each

const myCoding = [
    {
        languageName: "javascript",
        fileName: 'js'
    },
    {
        languageName: "python",
        fileName: 'py'
    },
    {
        languageName: "java",
        fileName: 'java'
    },
]

myCoding.forEach((item) => {
    console.log(`\({item.languageName} has a file name of \){item.fileName}`);
    
})

Output

javascript has a file name of js
python has a file name of py
java has a file name of java

filter

Unlike forEach() with filter() we can return a shallow copy (no reference) of a new array created with elements that got returned by the call back function. Always have a condition inside the filter callback function that returns true or false. If true that item is included in the new array that will be returned.

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

const newNums = myNums.filter((item)=>(item > 4)) // Implitcit here, if you use {} make sure to use return

console.log(newNums)    // [ 5, 6, 7, 8, 9, 10 ]

We can filter out based on the above condition with the help of forEach as well, let's check out an example

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

const newNums = []

myNums.forEach((item) => {
    if(item > 4){
        newNums.push(item)
    }
})
console.log(newNums)    // [ 5, 6, 7, 8, 9, 10 ]

Let's see another example where a user wants to filter books on a website based on certain criteria

const books = [
    { title: 'Book One', genre: 'Fiction', publish: 1981, edition: 2004 },
    { title: 'Book Two', genre: 'Non-Fiction', publish: 1992, edition: 2008 },
    { title: 'Book Three', genre: 'History', publish: 1999, edition: 2007 },
    { title: 'Book Four', genre: 'Non-Fiction', publish: 1989, edition: 2010 },
    { title: 'Book Five', genre: 'Science', publish: 2009, edition: 2014 },
    { title: 'Book Six', genre: 'Fiction', publish: 1987, edition: 2010 },
    { title: 'Book Seven', genre: 'History', publish: 1986, edition: 1996 },
    { title: 'Book Eight', genre: 'Science', publish: 2011, edition: 2016 },
    { title: 'Book Nine', genre: 'Non-Fiction', publish: 1981, edition: 1989 },
  ];


// If user wants to filter out all books in history genere

  let userbooks = books.filter((book)=>{
    if(book.genre === 'History'){
        return book
    }
  })

  console.log(userbooks)
  console.log('----------------')

// If user wants to filter out all books in Non-Fiction category that came after 1990

  userbooks = books.filter((book) => (book.genre === 'Non-Fiction' && book.publish > 1990))

  console.log(userbooks)

Output

[
  {
    title: 'Book Three',
    genre: 'History',
    publish: 1999,
    edition: 2007
  },
  {
    title: 'Book Seven',
    genre: 'History',
    publish: 1986,
    edition: 1996
  }
]
----------------
[
  {
    title: 'Book Two',
    genre: 'Non-Fiction',
    publish: 1992,
    edition: 2008
  }
]

Map and Chaining

Use .map() when you want to perform operations on array elements and return a new shallow copy array with modified items. Inside the function whatever you return replaces the original item in the array with itself.

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

const newNums = myNumbers.map((num) => {
    return num+10
})

console.log(newNums)

// [ 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 ]

To understand maps better let's implement our own map function.

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

const newNums = ourMap((item)=>(item+10))
console.log(newNums)

function ourMap(action){
    const newNumbers = []
    for(let i=0;i<myNumbers.length;i++){
        newNumbers.push(action(myNumbers[i]))
    }
    return newNumbers
}

chaining

You can stack maps and filters on top of each other.

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

const newNums = myNumbers
                .map((num) => (num * 10))
                .map((num) => (num+1))
                .filter((num) => num >= 40)

console.log(newNums)

Output

[
  41, 51,  61, 71,
  81, 91, 101
]

reduce

reduce returns one value only after traversing all the array elements. The function inside reduce returns a value that is retained by the accumulator in the next iteration and ultimately the accumulator is returned when all iterations are over.

const myNums = [1, 2, 3]

const myTotal = myNums.reduce(function (accumulator, currentval){
    return accumulator + currentval
}, 1)

console.log(myTotal) // 7

// 1 is the initial value of the accumulator

let's write the same solution using an arrow function

const myNums = [1, 2, 3]

const myTotal = myNums.reduce((accumulator, currentvalue) => (accumulator + currentvalue), 1)

console.log(myTotal) // 7

Another example

const order = [
    {dish: 'Pasta Carbonara',price:14, spicy: false, qty:2},
    {dish: 'Dragon Ramen', price:12, spicy: true, qty:1},
    {dish: 'Caesar Salad', price: 11, spicy: false, qty:3},
    {dish: 'Inferno Wings', price: 11, spicy: true, qty:2},
    {dish: 'Truffle Risotto', price:18, spicy: false, qty:1},
]

const onlySpice = order.reduce((acc, item)=>{
    const category = item.spicy ? 'spicy' : 'mild'
    acc[category].push(item.dish)
    return acc
},{spicy: [], mild: []})

console.log(onlySpice)
/*

{ 
spicy: [ 'Dragon Ramen', 'Inferno Wings' ], mild: [ 'Pasta Carbonara', 'Caesar Salad', 'Truffle Risotto' ] 
}
 
*/