简体   繁体   中英

Get frequencies of objects in an array using reduce and map

I'm trying to write a function which will take in an array and then return a map of the frequencies of each object in the array. For example, for the following array:

freqs([1, 2, 3, 7, 2, 7, 1, 2, 1]) 

it will return a map like the following:

Map {1 => 3, 2 => 3, 3 => 1, 7 => 2}

Here is what I have so far:

function freqs(items) {
    return items.reduce(function(prev, curr)
    {
        if (curr in prev)
        {
            prev[curr]++;
        }
        else
        {
            prev[curr]=1;
        }

        return prev.map();
    });

}

However, when I try to test it, I get the following error:

Uncaught TypeError: Cannot use 'in' operator to search for '1' in 1

What is causing this? Also, is my logic correct? I feel like I'm doing something wrong.

  1. If you don't provide an initial value to reduce , it will by default use the first element as the initial value. In your case, prev becomes 1 . Thats why you are getting this error. You should set the initial value to a Map object.

  2. prev.map() - I have no clue what the intention is

  3. When you do prev[curr] , you are using the prev as a normal JavaScript object. Maps don't have bracket notation to access their values.


Your fixed program would look like this

function freqs(items) {
  return items.reduce(function(prev, c) {
    if (prev.has(c)) {  // use `has` and `set` operations on Map objects
      prev.set(c, prev.get(c) + 1);
    } else {
      prev.set(c, 1);
    }
    return prev;    // return the map, so it will be prev for the next iteration
  }, new Map());    // Set the initial value to a new Map object
}

console.log(freqs([1, 2, 3, 7, 2, 7, 1, 2, 1]));
// Map { 1 => 3, 2 => 3, 3 => 1, 7 => 2 }

You are inconsistantly using c vs curr and p vs prev . You are using map the wrong way.
Instead, just return prev;
Next up, you need to set a initial value for the prev -variable. This should be an empty object {} as a second argument for reduce . Do this, and you should be fine.

function freqs(items) {
    return items.reduce(function(prev, curr)
    {
        if (curr in prev)
        {
            prev[curr]++;
        }
        else
        {
            prev[curr]=1;
        }

        return prev;
    },{});

}

You can use Array.prototype.reduce() to set property of object to value of array element, increment value for each matched element; Object.keys() , Array.prototype.forEach() to set value of Map

 var freq = (arr) => { var map = new Map(); var obj = {}; Object.keys(arr.reduce((obj, prop) => { return (prop in obj ? ++obj[prop] : (obj[prop] = 1)), obj }, obj)).forEach(el => map.set(el, obj[el])); return map }; var arr = [1, 2, 3, 7, 2, 7, 1, 2, 1]; console.log(freq(arr)); 

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