5

I have an array of objects like this:

[
{"question":"Q1","answer":"my answer 2"},
{"question":"Q1","answer":"my answer"}
{"question":"Q1","answer":"my answer"}
{"question":"Q2","answer":"answer 2"}
]

I would like to group by the question keys and return the counts of each answer.

e.g.

{
    "Q1": [{
        "answer": "my answer",
        "count": 2
    }, {
        "answer": "my answer 2",
        "count": 1
    }],
    "Q2": [{
        "answer": "answer 2",
        "count": 1
    }]
}

,

I am able to groupBy questions using: .groupBy("question") and count occurances of values using .countBy() but I am not sure how to combine the grouping and counting functions to achieve the desired output?

2
  • is "native javascript" approach allowed in your case? Commented May 16, 2016 at 10:32
  • Sure, although I am using lodash in this project would be interesting to compare how it could be done without. Commented May 16, 2016 at 11:34

3 Answers 3

7

You can start with _.groupBy(array, 'question') - then use .map

For example:

var arr = [
{"question":"Q1","answer":"my answer 2"},
{"question":"Q1","answer":"my answer"},
{"question":"Q1","answer":"my answer"},
{"question":"Q2","answer":"answer 2"}
];

var result = _(arr)
  .groupBy('question')
  .map(function(item, itemId) {
    var obj = {};
    obj[itemId] = _.countBy(item, 'answer')
    return obj
  }).value();

console.log(JSON.stringify(result, null, 2));

See the working version at: http://jsbin.com/wixoronoqi/edit?js,console

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

3 Comments

I think it would be better to use mapValues() instead of map(), and just return the countBy() value directly.
I wasn't aware of mapValues, but yes, it would be an improvement to use mapValues
With ES6: var obj = {}; obj[itemId] = _.countBy(item, 'answer'); return obj -> return {[itemId]: _.countBy(item, 'answer')}.
0

Here is a native/vanilla js solution to this problem, using Array.reduce(), with and without the spread operator.

With spread operator, immutable style :

const questions = [
  {"question":"Q1","answer":"my answer 2"},
  {"question":"Q1","answer":"my answer"},
  {"question":"Q1","answer":"my answer"},
  {"question":"Q2","answer":"answer 2"}
];

const groupedQuestions = questions.reduce( (g, q) => {
  return {
    ...g,
    [q.question]: {
      ...g[q.question],
      [q.answer] : (g[q.question] && g[q.question][q.answer] || 0) + 1
    }
  }
}, {})

document.write(JSON.stringify(groupedQuestions))

Without spread operator :

const questions = [
  {"question":"Q1","answer":"my answer 2"},
  {"question":"Q1","answer":"my answer"},
  {"question":"Q1","answer":"my answer"},
  {"question":"Q2","answer":"answer 2"}
];

const groupedQuestions = questions.reduce( (g, q) => {
  typeof g[q.question] !== "undefined" || (g[q.question] = {});
  typeof g[q.question][q.answer] !== "undefined" || (g[q.question][q.answer] = 0);
  g[q.question][q.answer] += 1;
  return g;
}, {})

document.write(JSON.stringify(groupedQuestions))

Comments

-2

A "native javascript" solution using Array.forEach and Array.push functions:

var arr = [{"question":"Q1","answer":"my answer 2"},{"question":"Q1","answer":"my answer"}, {"question":"Q1","answer":"my answer"}, {"question":"Q2","answer":"answer 2"}];

var result = {};
arr.forEach(function(v){
    var key = v['question'], Q = this[key], found = false;
    if (Q) {
        var len = Q.length;
        while (len--) {
            if (Q[len]['answer'] === v['answer']) {
                Q[len]['count']++;
                found = true;
            }
        }
        if (!found) Q.push({'answer': v['answer'], 'count' : 1});
    } else {
        this[key] = [];
        this[key].push({'answer': v['answer'], 'count' : 1});
    }
}, result);

console.log(JSON.stringify(result, 0, 4));

The output:

{
    "Q1": [
        {
            "answer": "my answer 2",
            "count": 1
        },
        {
            "answer": "my answer",
            "count": 2
        }
    ],
    "Q2": [
        {
            "answer": "answer 2",
            "count": 1
        }
    ]
}

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.