-1

Below is a code snippet which finds out "How many times each element of an array is repeated". Everything is working as expected except it doesn't give me "ebay repetition count"

var strArr = ["google","ebay","yahoo","google","ebay","facebook","facebook","google"];
var output= {};
strArr.forEach(function(element) {
    var count = 0;
    try{
        while(strArr.indexOf(element) !== -1){
            strArr.splice(strArr.indexOf(element),1);
            count++;

        }  
    }catch(e){
        console.log(e);
    }
 output[element] = count;
});
console.log(output);

I tried debugging it with debugger;, I figured out that the second element of the array is being skipped.

Expected Output:

google:3
ebay:2
yahoo:1
facebook:2

Actual Output:

google:3
yahoo:1
facebook:2
6
  • Looks like you're changing an array while iterating over it. That's a really bad idea. Commented Sep 11, 2017 at 22:43
  • 3
    You are modifying the array (with .splice()) in the middle of a forEach loop. This is causing some elements to be skipped, because the indices that existed when the forEach began are unrelated to the ones that exist now. Commented Sep 11, 2017 at 22:44
  • 1
    That’s probably because you mutate the array as you iterate it. Just use reduce as in this answer. Commented Sep 11, 2017 at 22:44
  • Can someone please explain why it is a bad idea to mutate an array while iterating it, and what is causing this issue in this case? I agree with everyone saying reduce is a best practice but I am not exactly looking for a best practice here. I am just trying to write simple javascript. Commented Sep 11, 2017 at 22:51
  • I personally wound't say it's a bad idea, you can iterate and change arrays at the same time, but you have to be aware of these gotchas. If you do want to mutate while iterating, you could have used a reverse for loop, removing items then wouldn't change the index positions. Commented Sep 11, 2017 at 22:54

4 Answers 4

5
  • ForEach take google from index 0:
  • you removed google from the list including zero
  • ForEach moves to index 1 which now has yahoo as ebay moved to index 0

Sorry for bad english

Sign up to request clarification or add additional context in comments.

4 Comments

Rule of thumb, never iterate over array using forEach if you are going to change it
This is a comment, not an answer.
it's a good enough answer for the question "What's wrong with this JavaScript Code (Arrays)?"
He asked for whats worng, I am telling him whats wrong. As far as I can see thats an answer
5

First you shouldn't change an array while iterating over it (as ChrisG mentioned in a comment), second there's really no need to loop in a loop. Use reduce instead

let strArr = ["google", "ebay", "yahoo", "google", "ebay", "facebook", "facebook", "google"];
let res = strArr.reduce(function(a, b) {
  a[b] = (a[b] || 0) + 1;
  return a;
}, {});

console.log(res);

1 Comment

As a supplement, there is a pretty good write up on map/reduce operations here: danmartensen.svbtle.com/javascripts-map-reduce-and-filter
0

instead of using reduce, you can use a simple loop:

let strArr = ["google", "ebay", "yahoo", "google", "ebay", "facebook", "facebook", "google"];
let output = {};
strArr.forEach(function(val) {
  output[val] = output[val] || 0;
  output[val]++;
});

console.log(output);

Comments

0

You can easily notice the issue by logging the result in the loop:

var strArr = ["google","ebay","yahoo","google","ebay","facebook","facebook","google"];
var output= {};
strArr.forEach(function(element) {
    var count = 0;
    while(strArr.indexOf(element) !== -1){
        strArr.splice(strArr.indexOf(element),1);
        count++;
        console.log(element, count, JSON.stringify(strArr)); // <-- added this line
    }  
    output[element] = count;
});
console.log(output);

As you can see, after the first item "google" is removed, the second item is not ebay, but yahoo! After yahoo is removed, the next item is not ebay, but facebook, and the array is left with ["ebay","ebay"].

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.