0

I'm having an array of

var c = [{name: 'John'}, {name: 'John'}, {name: 'Tom'}];

I want to use the reduce method and map to get this following result:

result = [
    { name: "John", occurence: 2 },
    { name: "Tom", occurence: 1 }
  ]

Here's an attempt I have tried but still not fully getting it. https://jsfiddle.net/joeSaad/up3ddfzz/

c = [{
  name: 'John'
}, {
  name: 'John'
}, {
  name: 'Simon'
}];

var d = c.reduce((countMap, word) => {
  countMap[word.name] = ++countMap[word.name] || 1;
  return countMap
}, []);

var e = c.reduce((countMap, word) => {
  q = [];
  countMap[word.name] = ++countMap[word.name] || 1;
  var p = {
    name: word.name,
    occurence: countMap[word.name]
  }
  q.push(p);
  return q
}, []);

console.log(e);

Help much appreciated. Thanks in advance

4
  • 1
    Did you forget to post the attempt? Commented Aug 1, 2016 at 22:16
  • @AndrewL. thanks! just edited the question Commented Aug 1, 2016 at 22:17
  • @mike-c it seems that the run now in my jsfiddle is not working.. Commented Aug 1, 2016 at 22:26
  • @JoeSaad What do you mean and why did you ping me? I didn't alter your JSFiddle code at all. I just copied it into a runnable snippet inside of your question. Commented Aug 1, 2016 at 22:27

1 Answer 1

3

You're definitely on the right track working with reduce, but I would separate the computations into two distinct steps

let c = [{name: 'John'}, {name: 'John'}, {name: 'Tom'}];

const pairs = o=> Object.keys(o).map(k=> [k, o[k]])

let count = c.reduce((acc, {name}) => {
  if (acc[name] === undefined)
    return Object.assign(acc, { [name]: 1 })
  else
    return Object.assign(acc, { [name]: acc[name] + 1 })
}, {})

var result = pairs(count).map(([name, occurences]) => ({name, occurences}))

console.log(result)
//=> [ { name: 'John', occurences: 2 }, { name: 'Tom', occurences: 1 } ]


You could abstract these behaviours into distinct functions like this

// convert an object to [[key,value]] pairs
const pairs = o=> Object.keys(o).map(k=> [k, o[k]])

// count unique instances of a property value in an array of objects
const countBy = (prop, xs)=> {
  return xs.reduce((acc, x)=> {
    let y = x[prop]
    if (acc[y] === undefined)
      return Object.assign(acc, { [y]: 1 })
    else
      return Object.assign(acc, { [y]: acc[y] + 1 })
  }, {})
}

// your data
let c = [{name: 'John'}, {name: 'John'}, {name: 'Tom'}]

// then chain it all together
let result = pairs(countBy('name', c)).map(([name, occurences]) => ({name, occurences}))

console.log(result)
//=> [ { name: 'John', occurences: 2 }, { name: 'Tom', occurences: 1 } ]


ES6 also offers Map which is pretty good for doing this kind of computation.

This code reads a little nicer to me and is a little more semantically correct. Our previous code was doing the exact same thing, only it was using a plain object. Map is a data structure specifically designed for this key->value data, so that makes Map a better choice.

The only problem with this is, if your codebase isn't already using Maps in some way, introducing them just for this might be the wrong move.

// convert a Map to an array of pairs
const mpairs = m=> [...m.entries()]

// countBy this time uses Map
const countBy = (prop, xs)=> {
  return xs.reduce((m, x)=> {
    let y = x[prop]
    if (m.has(y))
      return m.set(y, m.get(y) + 1)
    else
      return m.set(y, 1)
  }, new Map)
}

// your data
let c = [{name: 'John'}, {name: 'John'}, {name: 'Tom'}]

// then chain it all together
let result = mpairs(countBy('name', c)).map(([name, occurences]) => ({name, occurences}))

console.log(result)
//=> [ { name: 'John', occurences: 2 }, { name: 'Tom', occurences: 1 } ]

Sign up to request clarification or add additional context in comments.

2 Comments

This definitely works. Thanks @naomik I still am trying to understand why we have const pairs. We are not using it. Also i don't quiet get the second approach. Thanks again!
We are definitely using it pairs; read the code more closely. The second section was meant suggest that you should wrap this stuff up in a function so that it doesn't clutter up the rest of your code. I added some notes there and also added a third section which shows how to do the same computation using a more semantic data structure.

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.