1

I need to get the total count of each word in a string .

I wanted to achieve it using reducer since i am a beginner in the reduce method i could not solve it .

getWordOccurence = (str1) => {
  splitStr = str1.split(' ');
  let count=0;
  const wordCount = splitStr.reduce((acc, curr) => ({...acc,[curr]:count}),{})
  console.log(wordCount)
};

getWordOccurence('apple orange apple banana grapes ?');

Expected : {"apple":2,"orange":1,"banana":1,"grape":1}

ReNinja
  • 543
  • 2
  • 10
  • 27
  • 1
    Possible duplicate of [word frequency in javascript](https://stackoverflow.com/questions/30906807/word-frequency-in-javascript) – zer00ne May 23 '19 at 03:21
  • I really not recommend use reduce for this, you're doing a `foreach` but use `reduce`. – apple apple May 23 '19 at 03:27
  • @appleapple `reduce` produces a *new object*, thus the function remains pure. Calling a function that modifies the passed argument is usually not desired functionality. Also, `reduce` in this case is taking an `array` and converting it to the desired return type of `object`. – Tyler Roper May 23 '19 at 03:30
  • @TylerRoper no OP **is** modifying the argument, the `initialValue` argument. – apple apple May 23 '19 at 03:31
  • I suppose in this case, the passed string would not be modified with a `forEach`, though I still don't think that a `forEach` is a better alternative to a `reduce`. `forEach` requires you to initialize an empty object before iterating, iterate through the array to add items to it, and then return the final object. `reduce` combines all three of those into a single method. – Tyler Roper May 23 '19 at 03:32
  • @TylerRoper Oh, yes, OP is **not** modifying the argument. sorry. But @ MaheerAli's answer does. I might be confused. – apple apple May 23 '19 at 03:36
  • @appleapple The function in Maheer's answer does not modify the string. It can't - strings are **immutable**. His method doesn't return anything though. – Tyler Roper May 23 '19 at 03:38
  • @TylerRoper well, I mean modify the `accumulator`/`initialValue` argument in callback of `reduce`. – apple apple May 23 '19 at 03:39
  • @appleapple That's correct, but I think most people would argue that's better within a method like `reduce`. Judging by his comments, it seems intentional. Creating a new object for each iteration is more expensive and less efficient than updating a single object throughout. – Tyler Roper May 23 '19 at 03:46
  • @TylerRoper agree. – apple apple May 23 '19 at 04:12

3 Answers3

2

You can try using comma operator. I thinks its better to use comma operator to return accumulator rather than using spread operator.

const getWordOccurence = (str1) => {
  splitStr = str1.split(' ');
  const wordCount = splitStr.reduce((ac, x) => (ac[x] = ac[x] + 1 || 1,ac),{})
  console.log(wordCount)
};

getWordOccurence('apple orange apple banana grapes ?');

One line for the function will be

const getWordOccurence = (str) => str.split(' ').reduce((ac,a) => (ac[a] = ac[a] + 1 || 1,ac),{})

console.log(getWordOccurence('apple orange apple banana grapes ?'));
Maheer Ali
  • 35,834
  • 5
  • 42
  • 73
  • I am unable to understand the solution, could you add some description for steps please? – Rahul Nov 17 '22 at 11:51
0

You can String.prototype.split() the string and use Array.prototype.reduce() to obtain the result object

In case you need to exclude the non words you can do Regular Expression /[a-z]/i to check the String.prototype.match() c.match(/[a-z]/i)

Code:

const str = 'apple orange apple banana grapes ?';
const getWordOccurence = s => s.split(' ').reduce((a, c) => {
  if (c.match(/[a-z]/i)) { // Only words...
    a[c] = (a[c] || 0) + 1;
  }
  return a;
}, {});
const result = getWordOccurence(str);

console.log(result);
Yosvel Quintero
  • 18,669
  • 5
  • 37
  • 46
0

I'd like to post a pure reducer version.

const getWordOccurence = (str1) => {
  const splitStr = str1.split(' ');
  const wordCount = splitStr.reduce((acc, x)=>({...acc,[x]:acc[x]+1||1}),{})
  console.log(wordCount)
};

getWordOccurence('apple orange apple banana grapes ?');

otherwise, I recommend simply use accumulator and loop through object (you can always extract it to a function, like occurence or something, you don't even need to pass the {} then).

const getWordOccurence = (str1) => {
  const words = str1.split(' ');
  
  //function occurence(words){
  let acc={};
  for(let word of words)
    acc[word] = acc[word]+1 || 1
  //return acc}
  
  //const wordCount = occurence(words)
  const wordCount = acc //just in case you want a *const* result
  
  console.log(wordCount)
};

getWordOccurence('apple orange apple banana grapes ?');
apple apple
  • 10,292
  • 2
  • 16
  • 36