Gintas K
Gintas K

Reputation: 1478

Re-organize a javascript array of objects

I've got an array of question and different answers (which I build dynamically, so the number of entries and different answers can vary):

var qaArray = [
    { question: "Question", answer: "Answer A"},
    { question: "Question", answer: "Answer B"},
    { question: "Question", answer: "Answer B"},
    { question: "Question", answer: "Answer C"},
    { question: "Question", answer: "Answer A"},
    { question: "Question", answer: "Answer B"},
    { question: "Question", answer: "Answer C"},
    { question: "Question", answer: "Answer A"},
    { question: "Question", answer: "Answer B"},
]

I need a function to build another array object from this, which would hold the 'answer' and 'count', in this case it would be:

[
    { answer: "Answer A", count: 3 },
    { answer: "Answer B", count: 4 },
    { answer: "Answer C", count: 2 },
]

Is there an easy method to do this, without straight forward loops?

Upvotes: 4

Views: 38

Answers (4)

dashton
dashton

Reputation: 2704

You can use Map to key your answers then reduce over the data to get counts, like so:

var result = Array.from(qaArray.reduce((acc, { answer }) => {
  const current = acc.get(answer) || { answer, count: 0 };
  current.count++;
  return acc.set(answer, current);
}, new Map()).values());

console.log(result);

Upvotes: 1

Vipin Kumar
Vipin Kumar

Reputation: 6546

You can use reduce for this. Concept is to push element to accumulator if it doesn't exist and increment the count if it does.

Please find below solution

var qaArray = [
    { question: "Question", answer: "Answer A"},
    { question: "Question", answer: "Answer B"},
    { question: "Question", answer: "Answer B"},
    { question: "Question", answer: "Answer C"},
    { question: "Question", answer: "Answer A"},
    { question: "Question", answer: "Answer B"},
    { question: "Question", answer: "Answer C"},
    { question: "Question", answer: "Answer A"},
    { question: "Question", answer: "Answer B"},
]


result = qaArray.reduce((acc, item) => {
  var exist = acc.find(x => x.answer === item.answer);
  if (exist) {
    exist.count += 1;
  } else {
    acc.push({
      answer: item.answer,
      count: 1
    })
  }
  return acc;
}, []);


console.log(result);

Upvotes: 2

Faly
Faly

Reputation: 13346

If ES6 is not a problem, it can be done by:

var qaArray = [
    { question: "Question", answer: "Answer A"},
    { question: "Question", answer: "Answer B"},
    { question: "Question", answer: "Answer B"},
    { question: "Question", answer: "Answer C"},
    { question: "Question", answer: "Answer A"},
    { question: "Question", answer: "Answer B"},
    { question: "Question", answer: "Answer C"},
    { question: "Question", answer: "Answer A"},
    { question: "Question", answer: "Answer B"},
];

var result = [...new Set(qaArray.map(q => q.answer))].map(a => ({ answer: a, count: qaArray.filter(e => e.answer === a).length }));

console.log(result);

Upvotes: 3

emil
emil

Reputation: 6364

If you are looking for solution without reduce or forEach, here is a verbose way using lodash.

_.countBy will give you close result, but if you want to transform it into array as you want, use mapValues.

_.chain(qaArray)
.countBy('answer')
.mapValues(function(value, key) {
  return { answer: key, count: value }
})
.values()
.value()

Upvotes: 2

Related Questions