Bray
Bray

Reputation: 361

Could anyone explain to me how this function works?

Write a function capitals that takes a single string (word) as argument. The functions must return an ordered list containing the indexes of all capital letters in the string.

Example

Test.assertSimilar( capitals('CodEWaRs'), [0,3,4,6] );

My solution is this which is the simple for loop:

function capitals(word) {
    var ara = [];
    for(var i = 0; i < word.length; i++){
        if(word[i] == word[i].toUpperCase()){
            ara.push(i)
        }
    }
    return ara;
}

But I want to understand this one using higher order function:

function capitals(word) {
    return word.split('').map(function(item, i) {
        return item == item.toUpperCase() ? i : null;
    }).filter(function(x) {
        return x != null;
    });
}

especially the 'map(function(item, i)' part say why it knows i is the index without us defining it anywhere?

Thanks for your help!

Upvotes: 2

Views: 529

Answers (4)

kamituel
kamituel

Reputation: 35950

See code comments:

function capitals(word) {
  return word
          .split('')  // split a word in an array of letters
          .map(function(item, i) {
              // if letter is an upper case, return its index, null otherwise
              return item == item.toUpperCase() ? i : null;
          }).filter(function(x) {
              // filter out all null elements, effectively leaving only
              // indices of uppercase letters in a string.
              return x != null; 
          });
}

For an explanation of map(), see this MDN page. The function passed to map() is a callback which is taking three arguments - the element from an array over which map() is called, an index of this element in the array and an array itself.


Here's an example of map() itself. Consider this code:

var result = ['a', 'b', 'c', 'd'].map(function(element, index) {
  console.log('element ' + element + ' is at position: ' + index);
  return index % 2 === 0 ? element.toUpperCase() : element;
});

console.log(result);

It will print:

element a is at position: 0
element b is at position: 1
element c is at position: 2
element d is at position: 3 
['A', 'b', 'C', 'd']

Note that in this example we're using index parameter to capitalize only every other letter. Also note that map() would work with array of numbers, objects etc, not only letters.

Upvotes: 2

p.s.w.g
p.s.w.g

Reputation: 149010

why it knows i is the index without us defining it anywhere?

It actually is defined, within the map function. For every item in the source array, it will provide three parameters to the callback function that you pass in. From MDN:

callback

Function that produces an element of the new Array, taking three arguments:

  • currentValue
    The current element being processed in array.
  • index
    The index of the current element being processed in array.
  • array
    The array map was called upon.

Upvotes: 1

Ende Neu
Ende Neu

Reputation: 15773

map applies a function to each element of the collection, in your case after split you have an array of chars, item is the current char and i is the index, the first operation:

return item == item.toUpperCase() ? i : null;

Is applied to all chars and reads, if this char is upper case return the index, else return null (this syntax condition ? value : default is called ternary operator).

The second is a filter to remove the null values from the array leaving only the indexes.

Upvotes: 1

Valentin Waeselynck
Valentin Waeselynck

Reputation: 6051

That's the beauty of map: you don't have to write your for loop, it's already in the body of the map function.

The body of map contains a for loop which declares the index and "injects" it into the function you passed to it.

Upvotes: 1

Related Questions