Nested Loops vs. forEach iterator

As I’ve been stuck for way too long in the Mini Linter project, I’ve decided to trace back my steps and make sure that I’ve learnt everything that I should to face this particular practice.

In that journey, I was trying to compare loops and iterators to be able to finally understand the true nature of 'em both, and I’ve come with what is next. It’s kinda silly, I reckon, but it’s made me understand the nature of the forEach iterator (with I was kinda of struggling with beyond logging a bunch of sentences with the elements of an array).

Basically, all I’ve done is applying the forEach iterator to the “compare friends in social media” exercise. The result is as follows.

First, with the nested loops:

// Nested loops vs forEach iterator

// Nested loop

let nathaliaFriends = ['Ernest','Jack','Peter','Miley','Sally','Xavier'];
let johnFriends = ['Jesus','Ernest', 'Joe','Peter','James','Monica'];
let commonFriends = [];

function compareFriends (nathaliaFriends, johnFriends) {
    for (let i = 0; i < nathaliaFriends.length; i++) {
        for (let j = 0; j < johnFriends.length; j++) {
            if (nathaliaFriends[i] === johnFriends[j]) {
              commonFriends.push(nathaliaFriends[i]);
            }
        }
    }
    return commonFriends;
}

console.log(compareFriends(nathaliaFriends, johnFriends));

And then, with the forEach iterator:

// forEach iterator

let nathaliaPals = ['Ernest','Jack','Peter','Miley','Sally','Xavier'];
let johnPals = ['Jesus','Ernest', 'Joe','Peter','James','Monica'];
let commonPals = [];

nathaliaPals.forEach(pal => {
    if (johnPals.includes(pal)) {
        return commonPals.push(pal);
    }
});
console.log(commonPals);

The result seems to be the same, but I love to shorten code.

Now, my questions would be:

1.- As the result is the same, is the logic behind nested loops and the forEach iterator vastly differently? Or are the scenarios in which to use either one of them vastly different?

2.- .forEach is an iterator and .includes a method, right?

Thanks!

Cheers!

Excellent work on that refactor.

Not quite: .forEach() is still an array method, just like .includes(), but is used for iterating through the array.

As for your first question, I’d expect .forEach() to have very similar logic to a traditional for loop under the hood (not necessarily nested for loops - most uses I’ve had for them were equivalent to regular for loops).

If you wanted to iterate backwards through an array, .forEach() wouldn’t be a good choice, you’d want to use:

for (let i = array.length - 1; i >= 0; i--) { 
  array[i] = 'going backwards through the array';
}

Unless there’s some other array method I don’t know about.

Thanks a lot :slight_smile:

I am quite struggling with iterators, to be honest. Most of it, on that Mini Linter step #8.1.

I’ve found a piece of code in GitHub which I am trying to unravel in order to be able to achieve that step of the Mini Linter project… unsuccessfully so far :cry:

By the way, on that note, I do not want to move onwards till I am sure that I’ve been able to fix perfectly all previous knowledge on one hand. On the other, I believe that I should keep moving on in spite of my lack of total understanding of a few concepts, in such a manner that I will soon understand what I didn’t as I hopefully continue grasping some new concepts along the way… Any recommendation on this? I’ve found plenty of exercises to keep practicing JS (some little — and not so little — exercises, many of which still take me ages to complete :sweat:), but I don’t know if I should go ahead and try with objects before I have a full comprehension of how iterators work. It all seems as exciting as it seems complicated, hehe.

Anyway, thank you so much on your feedback :slight_smile:

About your further explanation, both .forEach() and .includes() are methods then, right?

I see how .forEach() can’t be used to loop thru arrays backwards. Thanks again :angel:

By the way, I know that policies about sharing links in these posts is kind of specific. I hope I haven’t violated them at all by sharing that one link from GitHub Otherwise, please, do let me know so that I can remove immediately :slight_smile:

Cheers!

You’ll get more practice with array methods in the Practice JavaScript Syntax: Arrays, Loops, Objects, Iterators section, so if you need to take a break to study them in more depth, I’d do it after that, since you might click while there. W3Schools has a section on array iteration, the Digital Ocean article is worth a bookmark, and just keep referencing the MDN docs.

That github code looks like it removes every other over used word, and not and not every other use of each overused word.

Exactly. Anything written like .methodName() is a method. Some methods are designed specifically for iteration (like .forEach()). It took awhile to come up with an example where for was better than .forEach().

I can’t actually find any specific rules on links. I assume it’s just the usual no self-promotion, spam, or scams rule. I’d expect GitHub to be okay. I tend to link to anything and everything that might be helpful.

Haha. That is true. We can always reverse the order of the array first and then iterate through them.

let arr =  [1,2,3,4,5];
arr.reverse(); // this is a mutator method which means it'll change the order of elements in the Array objects against which it is called.
arr.forEach(item => {
  // code for the each iteration.
})
arr.reverse(); // but we can call the method again to reverse the reversed order.

Now as to your question @ibaifernandez, they are both method of the Array class. But you can still iterate over them by doing these kind of things. Did you know you can call iterator method consecutively on an array? That seems like a good place to understand. Just know which iterators return an array and then you can call a new iterator against that returned array by the old iterator.

GitHub links are fine. As long as it is relevant to the idea of and/or understanding of programming, we can share the links. If you refer the community guidelines, it says that non code related external sites is a ‘don’t’. You can refer the full community guidelines at this link.

Hope that helps.

1 Like

Thanks a lot once again.

I will follow your advice, then: keep on going now with the objects section and stop after the “Practice JavaScript Syntax: Arrays, Loops, Objects, Iterators” section if I still need to go over and over and over some other concepts.

I will have a look at that W3Schools’ section on array iteration and definitively bookmark the Digital Ocean article as I keep referencing the MDN docs. Sometimes I just get lost at silly things, such as, for example, the use of var — as I’ve learnt const and let variable declarations. I know that var is just a former form to declare variables which I should get used to to understand older scripts, but I am too much of a newbie to adapt easily at the moment. It’s such a discovery trip, though… I am lovin’ each step of it :slight_smile:

About the GitHub code, I am not really sure of what it does as I can’t yet decipher it all properly. But I will get there! Stubbornness is one of those qualities that definitively defines me :wink:

I really want to thank you as well as this whole community to make this discovery trip such an enjoyable one :slight_smile: You people truly help to stay deeply motivated :slight_smile:

Cheers!

1 Like

Hi, @goku-kun :slight_smile:

Quite interesting to know. Would .reverse() be another method in this case? How many of the are out there to be learned? Seems to be like a never-ending list! Not that I am complaining about lots and lots of new things to learn… but it really blows my mind to think how much time I’ve wasted learning other skills which now, in comparison, seem to fade away before the how important and fun coding is… and how happy it makes me feel as I deeply understand something about it! :sweat_smile:

Also, having English not as my mother tongue — although kinda fluent in it —, I sometimes take a bit longer to understand things which, once understood, make me feel a bit stupid for not understanding them in the first reading :laughing:

I did not… I believe. Yesterday I tried a small exercise I found in W3Resource. It goes as follows:

let string = "Ibai's learnt to do something sorta cool tonite.";
let stringArr = string.split('');
let lastCharacter;

const change = (string) => {
    let lastCharacter = stringArr[stringArr.length - 1]
//    console.log(lastCharacter);
    stringArr.unshift(lastCharacter);
    stringArr.pop();
//    console.log(stringArr);
    let newString = stringArr.join('');
//    console.log(newString);
    return newString
}

console.log(change())

As you keep on logging the function consecutively, the sentence contained in the initial string loops over and over. It’s kinda cool, and I kinda can see the function of it on a website, for example, as I could make a slogan of some sort roll over and over back and forth, left to right.

Actually, something that powerfully draws my attention about coding is that, no matter which its applications can be, it’s just so freakin’ cool to resolve stuff as if I was facing some sort of twisted jigsaw with infinite pieces which I get to pick from! Anyways, I was showing that piece of code to see if there’s something related to what you mention about calling iterator methods consecutively. I think that little piece of code that I am displaying makes something alike.

Thanks for the advice on the link usage. Just checkin’ since the last thing I’d possibly want is to be kicked out of this forums. They’re just as fan to keep track of as coding is :heart_eyes:

Thanks a lot!

Cheers!

Hey, @ibaifernandez.

Yes, .reverse() is also another method of the JavaScript Array Object. You can checkout all the methods and descriptions and uses by using the MDNs documentation.

If you scroll down a bit, you’ll notice a section called ‘Instance methods’. If you noticed, you’ll find all the methods of Array object here including .forEach() and .reverse(). You can click on those links to find out more about these methods.

Well, you don’t actually have to remember all of them. That’s what the documentation is for. Just take a look at these methods and keep them at the back of your mind and you can always refer the syntax when you’re trying to use them.

The code that you’ve mentioned for reversing the string can be done easily using the .reverse() method.

Try using the .reverse() method to reverse the string without doing the steps you’ve mentioned above. Once you do, come back and refer the hint to see if you were able to do it. :slightly_smiling_face:

Hint

You can do something like this.

let string = "Ibai has learnt to do something sorta cool tonight.";
let stringArr = string.split('');
console.log(stringArr);
stringArr.reverse();
console.log(stringArr.join(''));

This will also print your string but it’ll be reversed.

Also, this piece of code that you mentioned has nothing to do what I said about calling the iterators consecutively. When I said calling the iterators consecutively, I meant something like this.

let arr = [1, 2, 3, 4, 5];
let sum_of_squares = arr.map(value => {
    return value ** 2; // squaring each element of arr and returning a new array
}).reduce((acc, nextValue) => {
    return acc + nextValue; // reducing all the elements to a single element by adding all the elements
})

console.log(sum_of_squares);
console.log(1 + 4 + 9 + 16 + 25);

Check this out. What do you think is going on here?

1 Like

We have an array. We declare a function using arrow syntax that calls the .map array method over each one of the elements of that array assigning them as the value parameter as it iterates thru it in such a way that every one of those values (this is, every element of that array) is gonna be multiplied by itself twice (this is, the squaring of each one of those specific values). Once this task is performed, the result of each one of those values is going to be iterated thru using another array method, .reduce() in this case, which will enable the sum of each one of the results of the .map array method iterating over the elements (values) of the array.

So, basically, the first logging will end up printing the same result as the second one for they’re actually the same thing.

Kinda? :heart:

I promise to have a look at the rest of your lovely answer tomorrow, as it’s getting late in this part of the world and clients will be chasing me since early tomorrow as Christmas seasons is badly tormenting the marketer who I am at daylight :laughing:

Thanks!

Edit: PS: I understand perfectly know what you mean by “calling iterator methods consecutively on an array” :partying_face:

1 Like

Hey, @ibaifernandez. Glad I could help. So, I hope you are clear about the difference between loops and iterators now although I’ve specified very little information about the topic. xD

And the answer that you wrote for my question is correct. :white_check_mark:
Practice enough with these topics that you’re comfortable using them. And if you still don’t understand something, always reach out and ask more questions.

Cheers,
Dharma

1 Like

Lovely, @goku-kun!

I still owe you a proper reading of all your words, but coding time is night time, so I will get back to it later on today :heart:

I am most definitely clear on the difference among loops and iterators. It’s just that freakin’ issue about removing every other repeated word from a text that is getting on my nerves these days. But I will get the freakin’ result soon enough (I hope!).

I’ve simplified the exercise to myself to see if I can get it in a smaller scale first. This is:

Let’s say that I have a string such as:

let story = "This is the real story of a real person in a real world doing real things."

That I convert into an array such as

let storyArr = story.split(' ');

So far so good.

I have another, let’s say, array, which is:

let repeat = ['real'];

And another variable:

finalStory = [];

So by the end of the exercise I should get:

console.log(finalStory); // Returns "This is the real story of a person in a real world doing things.

That’s all I am trying to get these days. Wish me courage (advise will be deeply appreciated, haha)!

Cheers!

1 Like

Hey, @ibaifernandez.
Did you work on it? How did it go?

1 Like

Dear @goku-kun,

not yet, regrettably. As the Christmas Day approaches, clients are squeezing me out 24/7 lately and I end up my days all beaten up. Y’day, I only managed to take a peek at the JS objects lesson, which felt quite difficult.

So, either if you mean reading your words fully or trying with my “remove every other repeated word” exercise, I didn’t have time for it :cry:

I hope Christmas day to come and definitively go so that I can have a good break to keep on working on figuring out (and learning) more stuff.

Thanks for writing! I will get back to you quite soon :wink:

Cheers!

Nevertheless, the code I mentioned earlier in this thread — and which I am referencing again, just to avoid confusions — is not supposed to reverse a string as such. It’s supposed to take the last character of a string and to put it at the beginning so (I suppose) you get one of those “crawling text” effects when you get to animate on its own (it may be obvious that I don’t truly know yet what I am actually talking about :sweat_smile:) :slight_smile: I guess that I should’ve said “rotate” rather than “reverse” :sweat_smile: The exercise actually states “Rotate the given string in right direction by periodically removing one letter from the end of the string and attaching it to the front.” This is the code:

let string = 'Ibai ha aprendido a hacer algo chévere.';
let stringArr = string.split('');
let lastCharacter;

const change = (string) => {
    let lastCharacter = stringArr[stringArr.length - 1]
    stringArr.unshift(lastCharacter);
    stringArr.pop();
    let newString = stringArr.join('');
    return newString
}

console.log(change())

I am now attaching an image of the result of consecutive loggings:

String inversion

[Sorry about the Spanish, but I believe it properly shows what I mean :sweat_smile: ]

So, anyways, this was just to say that I don’t know if the same result could be achieved with .reverse(). Actually, before having a look at your hint, this is what I did:

let string = 'Ibai ha aprendido a hacer algo chévere.';
let stringArr = string.split('');
let newArray = [];
let newString;

newArray = stringArr.reverse()
newString =  newArray.join('');

console.log(newString);

For what I can see, I just gave couple more — probably unnecessary — turnarounds, but I kinda got it, right? :slight_smile:

Finally, once again, I definitely see what “calling iterators consecutively” means :slight_smile:

Now, I am gonna go ahead and try to remove every other repeated word of a sentence… Let’s see if I get it :muscle:

Thanks a lot, @goku-kun

1 Like

Hey, @ibaifernandez!
Oh, I thought that you were just reversing the string and that was the end goal of the code that you wrote. Sorry, that was a wrong presumption on part. But, as I said, .reverse() method is just used to reverse the content of an array and it certainly doesn’t rotate the content like you want it to.
Repeated word of a sentence is a cool exercise. Even, it took me a while to reach a solution on my own. So, don’t worry if you don’t get the correct answer at the very first time. Keep working on it. Start small; First try only eliminating one single word like ‘real’ every other time as you said in this example below:

Let me know how that goes. xD
And also post the solution in the forums if you’re able to solve it!

Dear @goku-kun,

I am kinda giving up on this one :cry:

I can remove words contained in an array every time they show up, but not every other time they appear.

Thus, that step #8.1 of the Mini-Linter became my nemesis.

I’ve already entered the world of objects, but I hate this sensation of leaving something important behind :frowning:

I’ve also tried to crack that piece of code that I found in GitHub, but I don’t understand what’s going with it at all.

This image comes from my VSC, which is set up with Quokka, which yields me some results as I code. Well, I am attaching the image just to say that I don’t what’s going on with all those arrays there… And that’s why I say I can’t crack it, for I can’t understand one single thing it does :cry:


The code comes next. I've made up a bit the exercise as it is stated in Codecademy with a shorter *story* but another array of words to be removed. It can't get pretty untidy at times, I am afraid.
let story = "This literally is a really really cool real story of a very awesome real person in a basically real world actually doing extremely real things."

let overusedWords = ['really', 'very', 'basically'];

let unnecessaryWords = ['extremely', 'literally', 'actually' ];

let repeatedWords = ['real', 'cool', 'awesome']

let storyWords = story.split(' ');

console.log(storyWords);

console.log('The original story contains ' + storyWords.length + ' words.');

// Remove Unnecessary words

let storyWithoutUnnecessaryWords = storyWords.filter(word => !unnecessaryWords.includes(word));

console.log(storyWithoutUnnecessaryWords)

console.log(storyWithoutUnnecessaryWords.join(' '))

console.log('The story contains ' + storyWithoutUnnecessaryWords.length + ' words after removing unnecessary words.');

// Count and log overused words

overusedWords.forEach(overusedWord => {
    let overusedWordsCount = 0;
    storyWithoutUnnecessaryWords.filter(storyWord => {
        if (overusedWord === storyWord) {
            overusedWordsCount++;
        }
    });
    if (overusedWordsCount != 1) {
        console.log('The word ' + '"' + `${overusedWord}` + '"' + ' was used ' + overusedWordsCount + ' times.');
    } else {
        console.log('The word ' + '"' + `${overusedWord}` + '"' + ' was used ' + overusedWordsCount + ' time.');
    }
});

// Count sentences

let sentenceCount = 0
storyWithoutUnnecessaryWords.forEach(word => {
    if (word[word.length-1] === '.' || word[word.length-1] === '!') {
        sentenceCount++;
    }
});

console.log('There are ' + (sentenceCount) + ' sentence(s) in the story.');

// REMOVE AND REPLACE EVERY OTHER INSTANCE OF CERTAIN WORDS AS CONTAINED IN THE GIVEN ARRAYS.

// Create an array with .map() and save to a new variable and create a variable to store the counter of removed words

let repeatedWordsCounter = repeatedWords.map(function() {
    return 0;;
  });

let removedRepeatedWords = 0;

let storyWithNoUnnecessaryWordsAndNoRepeats = storyWithoutUnnecessaryWords.map(finalStoryWord => {
    if (!repeatedWords.includes(finalStoryWord)) {
      console.log(finalStoryWord);
      return finalStoryWord;
    } else {
      let position = repeatedWords.indexOf(finalStoryWord);
      console.log(position)
      if (repeatedWordsCounter[position] < 1) {
        console.log(repeatedWordsCounter)
        repeatedWordsCounter[position]++;
        console.log(repeatedWordsCounter)
        return finalStoryWord;
      } else { 
        repeatedWordsCounter[position] = 0;
        removedRepeatedWords++;
        console.log(removedRepeatedWords)
        console.log(repeatedWordsCounter)
        return '';
       }
    }
  });

let overusedWordsCounter = overusedWords.map(function() {
  return 0;;
});

let removedWordsCounter = 0;

let storyWithNoUnnecessaryWordsNoRepeatsAndOnlyHalfOfTheOverusedWords = storyWithNoUnnecessaryWordsAndNoRepeats.map(storyWord => {
  if (!overusedWords.includes(storyWord)) {
    console.log(storyWord);
    return storyWord;
  } else {
    let position = overusedWords.indexOf(storyWord);
    console.log(position)
    if (overusedWordsCounter[position] < 1) {
      console.log(overusedWordsCounter)
      overusedWordsCounter[position]++;
      console.log(overusedWordsCounter)
      return storyWord;
    } else { 
      overusedWordsCounter[position] = 0;
      removedWordsCounter++;
      console.log(removedWordsCounter)
      console.log(overusedWordsCounter)
      return '';
     }
  }
});

console.log(story);
console.log(storyWithoutUnnecessaryWords.join(' '));
console.log(storyWithNoUnnecessaryWordsAndNoRepeats.join(' '));
console.log(storyWithNoUnnecessaryWordsNoRepeatsAndOnlyHalfOfTheOverusedWords.join(' '));

What does this part do, step by step? Where all those arrays shown in the image comes from? Is there an easier — more understandable — way to do it?

Cheers!