2

Can someone explain the following code? inputWords is supposed to be an array containing various words and this function is supposed to return an array containing the number of times a word appears in inputWords.

ie. var inputWords = ['Apple', 'Banana', 'Apple', 'Durian', 'Durian', 'Durian']

console.log(countWords(inputWords))
// =>
// {
//   Apple: 2,
//   Banana: 1,
//   Durian: 3
// }

I understand what the Reduce function does, but what is resultObj[word] = ++resultObj[word] || 1; doing?

Thanks so much :)

function countWords(inputWords) {
  return inputWords.reduce(function(resultObj, word) {
    resultObj[word] = ++resultObj[word] || 1;
    return resultObj;
  }, {});
}

module.exports = countWords;
4
  • 6
    It increments resultObj[word] if it exists, otherwise initializes it to 1. Commented Jun 2, 2014 at 18:14
  • 1
    || is the logical or operator, will pick the 1 if the left side is a falsy value Commented Jun 2, 2014 at 18:15
  • @vladkras reduce is actually the operation of applying a function to aggregate a collection to a single value, in this case an array with many words to an object counting how many times each word appears in the array. The increment is what actually does the counting. Commented Jun 2, 2014 at 18:22
  • 3
    Could as well be written as resultObj[word] = (resultObj[word] || 0) + 1 which gets the intention better across. Commented Jun 2, 2014 at 18:23

3 Answers 3

3

The code attempts to assign to a key (that may not yet exist) an incremented value (of a key that may not yet exist), of if that it that is falsey, it assigns a 1.

This is called short-circuit evaluation. Given a = b || c, if b is truthy, c never gets evaluated so a takes on the value of b. If b is falsey, c is evaluated and assigned to a instead. In your case, when the key doesn't exist, ++resultObj[word] is falsey.

In my humble opinion, I think that it would have been a clearer statement of the author's intention if they had instead done:

if (word in resultObj) {
    ++resultObj[word];
}
else {
    resultObj[word] = 1;
}

or even:

resultObj[word] = word in resultObj ? resultObj[word] + 1 : 1;

either of which would have saved you the bother of asking this question.

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

Comments

1

It's 'defaulting' a non-existent key in resultObj to 1.

Javascript's || will actually return the first (leftmost) truthy value out of a comparison, so for a nonexistant value added one by the preincrement operator such as ++resultObj['banana'] returns NaN, which is falsey, and the || operator will replace it with 1.

Edit: See http://nfriedly.com/techblog/2009/07/advanced-javascript-operators-and-truthy-falsy/

Comments

1

I would write:

resultObj[word] = (resultObj[word] || 0) + 1;

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.