3

I am trying to get a paragraph and turn it into words and also realize the frequency of each.

var pattern = /\w+/g,
  string = "mahan mahan mahan yes yes no",
  matchedWords = string.match(pattern);

/* The Array.prototype.reduce method assists us in producing a single value from an
   array. In this case, we're going to use it to output an object with results. */
var counts = matchedWords.reduce(function(stats, word) {

  /* `stats` is the object that we'll be building up over time.
     `word` is each individual entry in the `matchedWords` array */
  if (stats.hasOwnProperty(word)) {
    /* `stats` already has an entry for the current `word`.
       As a result, let's increment the count for that `word`. */
    stats[word] = stats[word] + 1;
  } else {
    /* `stats` does not yet have an entry for the current `word`.
       As a result, let's add a new entry, and set count to 1. */
    stats[word] = 1;
  }

  /* Because we are building up `stats` over numerous iterations,
     we need to return it for the next pass to modify it. */
  return stats;

}, {})

var dict = []; // create an empty array
// this for loop makes a dictionary for you
for (i in counts) {
  dict.push({
    'text': i
  });
  dict.push({
    'size': counts[i]
  });

};

/* lets print and see if you can solve your problem */
console.log(dict);

the dict variable returns:

[ { text: 'mahan' },{ size: 3 },{ text: 'yes' },{ size: 2 },{ text:'no'},{ size: 1 } ]

but I am using a data visualization code and i need to turn the result into something like this:

[ { "text": "mahan" , "size": 3 },{ "text: "yes", size: 2 },{ "text":'no', "size": 1 } ]

I know it is basic but I am just an artist trying to use some code for a project. I appreciate your help.

1
  • 3
    Then dont use two separate objects: push({text:i,size:counts[i]}) Commented Aug 23, 2017 at 14:10

5 Answers 5

3

simply do:

dict.push({'text':i, "size": counts[i]});
Sign up to request clarification or add additional context in comments.

Comments

1

Your problem is that you are pushing two different objects in the array, to fix that you need to push only one object as mentioned in comments.

And instead of using a for loop you can do it in a better way using .map() on Object.keys(counts):

var dict = Object.keys(counts).map(function(k){
    return {text: k, size: counts[k]};
});

Demo:

var pattern = /\w+/g,
    string = "mahan mahan mahan yes yes no",
    matchedWords = string.match( pattern );

var counts = matchedWords.reduce(function ( stats, word ) {
    if ( stats.hasOwnProperty( word ) ) {
        stats[ word ] = stats[ word ] + 1;
    } else {
        stats[ word ] = 1;
    }
    return stats;
}, {})


var dict = Object.keys(counts).map(function(k){
    return {text: k, size: counts[k]};
});

console.log(dict);

Comments

1

You could also build up a hash table ( as a Map) and the resulting array in parallel, which may be faster:

let pattern = /\w+/g,
  string = "mahan mahan mahan yes yes no",
  matchedWords = string.match(pattern);

let hash = new Map(), result = [];

matchedWords.forEach( word => {
  if(hash.has(word)){
    hash.get(word).size++;
  }else{
    var tmp = { text: word, size: 1};
    hash.set(word,tmp);
    result.push(tmp);
  }
});

Try it

2 Comments

thanks. does any of the codes above support rtl languages? I am facing "matchedWords is null" when I Try it
@mahanmeh probably the regex is failing with left to right languages. My code will work either.
1

You are pushing two objects for every iteration. Don't do that. To fix your code, do what @asdf_enel_hak proposed in his answer, if you want to simplify your code, you could do that a bit easier and with less code.

let pattern = /\w+/g,
  string = "mahan mahan mahan yes yes no",
  matchedWords = string.match(pattern);

let res1 = [...matchedWords.reduce((a, b) => a.set(b, (a.get(b) || 0) + 1), new Map)].map(e => ({
  text: e[0],
  size: e[1]
}));

console.log(res1);

3 Comments

thanks, it's quite hard for me to understand what you did. But it also works perfectly.
array to map to 2d array to object array should be faster? ( if you claim it, proove it...)
@Jonasw edited to answer to better reflect what I've meant... Not sure if it's faster in terms of performance, but it's definitely faster to write... :)
0

This is rather tangential to the actual question, but you could condense that quite a bit. The following example is basically the same thing just condensed, and I've used a Tagged Template Literal for some extra syntactic sugar.

const frequency = s => s[0].match(/\w+/g).reduce((m, e) => ((m[e]=(m[e]||0)+1),m), {});

console.log(frequency`
Hello foo bar world!
Hello zoo bar world!
Hello foo car world!
Hello foo bar forld!
`);

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.