1

This JavaScript code tries to get the indices of a given value 5 in a new array. Any idea how to do it in an elegant way. I cold use for loop but I was hoping to use map or reduce. thx.

console.log( [1, 2, 3, 5, 6, 5].map((y, i) => {
  if (y === 5) return i
}))
// gives --> [undefined, undefined, undefined, 3, undefined, 5]
// expected [3,5]

6 Answers 6

2

Unfortunately map and reduce are not lazily-evaluated in JavaScript (i.e. they're not generators/iterators), but if you don't mind the double array allocation, you can do this:

var indices = [ 1, 2, 3, 5, 6, 5 ]
    .map( ( e, i ) => e == 5 ? i : -1 )
    .filter( e => e > -1 );

// indicies == [3,5]

Another approach, that's cheaper:

var indices = [];
[ 1, 2, 3, 5, 6, 5 ].forEach( (e, i) => e == 5 ? indices.push( i ) : null );

This takes advantage of the fact you can use a void expression inside the ?: ternary operator.

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

2 Comments

is forEach in this case cheaper than the for loop I posted?
@FredJ. There is no for loop in your question. You have to define "cheap" for an answer. The simplest solution would be a for loop. I would go with .reduce() to only iterate the array once.
2

You can use reduce. The third argument of the callback is the index.

[1, 2, 3, 5, 6, 5].reduce((indexes, n, index) => {
  if (n === 5) indexes.push(index)
  return indexes
}, [])

Comments

2

You can either use map() or reduce().

reduce() will be able to do it in a single loop:

[1,2,3,4,5].reduce((result, num, index) => result.concat(num === 5 ? index : []), []);

Using concat() instead of push() is a tiny bit slower, but cleaner, and in reasonably small sets, the difference will be negligible.

map() will need filter() to remove extras:

[1,2,3,4,5].map((num, index) => num === 5 && index)
    .filter(e => e !== false);

.filter(Boolean) is a clean, short-hand way of casting whatever value to a Boolean, which filter will then use to determine what it needs to do. num === 5 && index will be either false or the index. Another clean way to go through.

2 Comments

Using the second method, if we have [5, 1, 5], it returns [2]. Because Boolean(0) is false
Oops, indeed. Good catch. Fixed.
1

You can use reduce operator on your array as:

 [1,2,3,5,6,5].reduce(function(a, e, i) {
        if (e === 5)
            a.push(i);
        return a;
    }, []);

Comments

1

You could run a map to test the value and write either a null (no match) or the position (match) then a filter to remove the nulls.

The map would look like this:

map( (value, index) => {
  return value === 5 ? index : null;
})

Then you'd filter it like this:

filter( (value) => {
  return value != null;
})

Comments

1

console.log( [1, 2, 3, 5, 6, 5].map((y, i) => {
  if (y === 5) return i
}).filter((x) => {return /\d/.test(x);}));

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.