1

Here is my code:

function iLoveThree (array) {
  var threes = [];
  var x;
  for (x in array) {
    if (x % 3 == 0) {
      threes.push(x)
    }
  }
  return threes
}

When I pass the array [1,2,3,4,5,6,7,8,9] I get the following:

Function returned 
["0","3","6"]
instead of 
[3,6,9]

My question is, where are these double quotes coming from?

standin
  • 21
  • 9

8 Answers8

2

for...in is a bad way of iterating array indices. Better use filter:

[1,2,3,4,5,6,7,8,9].filter(function(x) {
  return x % 3 == 0;
}); // [3, 6, 9]
Oriol
  • 274,082
  • 63
  • 437
  • 513
  • Can you tell me why `for...in` is bad? Douglas Crockford also doesnt recommend it, I cant recall why though. – Rahul Desai Dec 08 '15 at 18:37
  • 1
    @RahulDesai See [Why is using “for…in” with array iteration such a bad idea?](http://stackoverflow.com/q/500504/1529630). In this case `for...in` would be problematic because it does not guarantee any order, so the result would beimplementation dependent. – Oriol Dec 08 '15 at 18:41
0

So basically in x in array x is the index not the array value. Because anyway 0 is not in the array but your function is returning it as well. You should instead access the values using array[x]

There are various approaches, one of them is using .filter

function iLoveThree(array){
    return array.filter(function(x){
        return (x%3==0?1:0);
    });
}

Or

function iLoveThree (array) {
  var threes = [];
  var x;
  [].forEach.call(array, function(x){
    if (x % 3 == 0) {
      threes.push(x)
    }
  }
  return threes
}
void
  • 36,090
  • 8
  • 62
  • 107
0

You're using a for..in loop which gives you the keys in an object, or in this case and array. Keys are always strings. Instead, you want to use a standard for loop.

for (var i = 0; i < array.length; i++) {
  var x = array[i];
  if (x % 3 === 0) {
    threes.push(x);
  }
}

Or if you want to use a more functional approach, you could use Array.prototype.filter.

return array.filter(function(x) {
  return x % 3 === 0;
});
Mike Cluck
  • 31,869
  • 13
  • 80
  • 91
0

A for..in loop does not loop through the array elements, it loops through the indices of the array. So for:

var arr = ["a", "b", "c"]
for ( x in arr ) console.log( x );

You'll get the string keys of ["0", "1", "2"]

You can fix your code by replacing your loop with a native for loop:

for ( var x = 0; x < array.length; x++ ) {
    if (array[i] % 3 == 0)
        threes.push(array[i]);
}
TbWill4321
  • 8,626
  • 3
  • 27
  • 25
  • This worked! Thank you. I had almost the same exact code earlier but I was using array[count] instead of a variable. Which is what @void said in his comment above. – standin Dec 08 '15 at 18:39
  • Crockford has recommended `array.forEach` over the traditional `for` loop. Just an FYI. – Rahul Desai Dec 08 '15 at 18:47
0

It seems that you are pushing in the indexes and not the actual values, go ahead and try the following:

function iLoveThree(array) {
    var threes = [];
    var x;
    for (x in array) {
        if (((x-2) % 3) == 0) {
            threes.push(array[x])
        }
    }
    return threes;
}

Another option, shorter, is:

function iLoveThree(arr) {
    var threes = [];
    for (var i = 2; i < arr.length; i = i + 3) {
        threes.push(arr[i]);
    };
    return threes;
}

if you are comfortable with callback/predicate based loops, you could make stuff even shorter by filtering the array, instead of creating a new one:

function iLoveThree(arr) {
    return arr.filter(function(x) {
        return (x % 3) == 0;
    });
}
Selfish
  • 6,023
  • 4
  • 44
  • 63
0

Not an answer to your question directly, but here's a nice way to pull every multiple of 3 from an array of numbers:

[1,2,3,4,5,6,7,8,9].filter(item => item % 3 === 0)

Adrian Lynch
  • 8,237
  • 2
  • 32
  • 40
0

Before you read the answer below, please read: Why is using “for…in” with array iteration such a bad idea? (Thanks to @Oriol for this link.)

Douglas Crockford has also discouraged the use of for..in. He recommends using array.forEach instead.

function iLoveThree (array) {
  var threes = [];

  array.forEach(function(item, i){  // use forEach, 'item' is the actual value and 'i' is the index
    if (item % 3 === 0) {
      threes.push(item); // you missed ; here
    }
  });

  return threes;  // you missed ; here
}

console.log(iLoveThree([1,2,3,4,5,6,7,8,9]));

Read up: Array.prototype.forEach() | MDN

Community
  • 1
  • 1
Rahul Desai
  • 15,242
  • 19
  • 83
  • 138
-1

If you read the for...in documentation, you will realize that you are pushing to threes the indexes (also called keys) not the values, because the variable x represents the index, so the value should be accessed by array[x].

function iLoveThree (array) {
  var threes = [];

  for (var x in array) {
    if (array[x] % 3 == 0) {
      threes.push(array[x])
    }
  }
  return threes
}

There are several ways to achieve this, the best one is by using a filter, but that way was already explained by someone else, therefore I will use an exotic implementation using a reduce

[1, 2, 3, 4, 5, 6, 7, 8, 9].reduce(function(acc, e){return e % 3 == 0 ? acc.concat(e) : acc}, [])

Outputs 3, 6, 9

Alberto Bonsanto
  • 17,556
  • 10
  • 64
  • 93