简体   繁体   中英

Can someone explain how the reduce method is working in this Functional JavaScript challenge?

According to the documentation of reduce..

The reduce() method applies a function against an accumulator and each value of the array (from left-to-right) to reduce it to a single value.

And this is the task:

Given an Array of strings, use Array#reduce to create an object that contains the number of times each string occured in the array. Return the object directly (no need to console.log).

Example

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

 console.log(countWords(inputWords))

   // =>
    // {
    //   Apple: 2,
    //   Banana: 1,
    //   Durian: 3
    // }

This is the solution:

function countWords(inputWords){
  return inputWords.reduce(function(wordCount, currentValue){
    if (!wordCount[currentValue]){
      wordCount[currentValue] = 1;
    } else {
      wordCount[currentValue] = wordCount[currentValue] + 1;
    }
    return wordCount;
  },{});
}

module.exports = countWords;

Isn't each indice in the array a 'string'? How is the object being created? I get how the iterator is being achieved, but can someone explain what's happening?

Every call of the function passes the last result, wordCount , and the current element of the array. The second parameter of reduce passes the initial value of wordCount , which in this case is an empty object literal.

Reduce will call the function for each element. With each call wordCount is updated and returned and passed as wordCount on the next call. Updating wordCount in the function won't effect wordCount on the next call, what ever is returned is what will be set to wordCount on the next call .

Here's how it looks with each pass (values and variables shortened from example to fit):

index | curVal | wordCount                        | (returned)
----------------------------------------------------------------------------
0     | 'App'  | { }                              | {'App':1}    
1     | 'Ban'  | { 'App': 1 }                     | {'App':1,'Ban':1}   
2     | 'App'  | { 'App': 1, 'Ban': 1 }           | {'App':2,'Ban':1}   
3     | 'Dur'  | { 'App': 2, 'Ban': 1 }           | {'App':2,'Ban':1,'Dur':1 }
4     | 'Dur'  | { 'App': 2, 'Ban': 1, 'Dur': 1 } | {'App':2,'Ban':1,'Dur':2 }
5     | 'Dur'  | { 'App': 2, 'Ban': 1, 'Dur': 2 } | {'App':2,'Ban':1,'Dur':3 }

The value returned is { 'Apple': 2, 'Banana': 1, 'Durian': 3 }

The reduce function takes two parameters:

  1. Callback(previousValue, currentValue, currentIndex, array)
  2. Initial value

Whatever value is returned from the callback function is then passed in to the callback function in the wordCount position.

In this example ... your currentValue is initialized with an object literal (second parameter of the reduce function).

After that ... it returns the updated object literal every time and thus, builds it's state.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce

A good way to see the state being built is to put a console.log at the end of the callback function.

Check out this JSFiddle (and look at the Debugger console).

 function countWords(arr) {
     const yourObject = new Object();
     let value = inputWords.reduce((a,val,index) => {
          if(index==1){
               yourObject[a]=1;
          }
          if (val in yourObject){
               yourObject[val]=++yourObject[val];
          }else{
               yourObject[val]=1;
          }
           });
     return yourObject;

The 2nd argument passed to reduce is the "initialValue", and you are passing {} (an instance of an empty object). On each call to your function, "wordCount" will be this object. In JavaScript, you can reference properties of an object with bracket/string notation like this:

someObject["someProperty"] = 2;
// ...is the same as
someObject.someProperty = 2;

So, if you were to peek in on your first and third iterations of your function, they would look something like this:

if (!wordCount["Apple"]){
  // On first iteration, wordCount.Apple will be undefined, so set to 1
  wordCount["Apple"] = 1;
  // Object is now { Apple: 1 }
} else {
  // On 3rd iteration, wordCount.Apple will already be 1, so we'll increment to 2
  wordCount["Apple"] = wordCount["Apple"] + 1;
  // Object is now { Apple: 2, Banana: 1 }
}
return wordCount;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM