FlameDra
FlameDra

Reputation: 2087

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.

Upvotes: 2

Views: 1389

Answers (3)

guest271314
guest271314

Reputation: 1

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));

Upvotes: 1

thefourtheye
thefourtheye

Reputation: 239573

  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 }

Upvotes: 3

Syntac
Syntac

Reputation: 1777

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;
    },{});

}

Upvotes: 1

Related Questions