2

I need to count each value on the object array , the desired output should be like below

[{
    "question": "question1",
    "USA": 2
  }, {
    "question": "question1",
    "AUS": 1
  },

  {
    "question": "question2",
    "item1": 2
  },

  {
    "question": "question2",
    "item1,item2": 1
  }, {
    "question": "question4",
    "3": 1
  }, {
    "question": "question4",
    "2": 1
  }
]

Below is the input I need to transform in to the above output. I have no clue how to do with n no of question and also got issue when one question has 2 answers . sample input

[{"question1":"USA","question2":["item1"],"question4":2}, 
{"question1":"USA","question2":["item1"],"question4":3}, 
{"question1":"AUS","question2":["item1","item2"]}];

let arr=[{"question1":"USA","question2":["item1"],"question4":2},{"question1":"USA","question2":["item1"],"question4":3},{"question1":"AUS","question2":["item1","item2"]}];
//console.log(arr);



function solve(list){
    var map = new Map();
    var entry = null;
    for(var item of list){
        if(!map.has(item.question1))
            map.set(item.question1, {question:'question1'});

            entry = map.get(item.question1);

        if(entry.hasOwnProperty(item.question1))
            entry[item.question1] = entry[item.question1] + 1;
        else
            entry[item.question1] = 1;
            
         
          if(!map.has(item.question2))
            map.set(item.question2, {question: 'question2'});

            entry = map.get(item.question2);

        if(entry.hasOwnProperty(item.question2))
            entry[item.question2] = entry[item.question2] + 1;
        else
            entry[item.question2] = 1;
         
    }
    return Array.from(map.values());
}
console.log(solve(arr))

2
  • 1
    It's not JSON - it's a normal JavaScript array of objects. Commented Mar 21, 2019 at 7:04
  • ^^ JSON is a textual notation for data exchange. (More here.) If you're dealing with JavaScript source code, and not dealing with a string, you're not dealing with JSON. Commented Mar 21, 2019 at 7:04

3 Answers 3

2

You could take an object or what ever data structure you like which supports a key/value structure in a nested style and collect first all items and then reder the collected tree.

This approach uses objects, because the keys are strings, this is important for an array as key. This is joint with a comma which is sufficient for this use case.

var data = [{ question1: "USA", question2: ["item1"], question4: 2 }, { question1: "USA", question2: ["item1"], question4: 3 }, { question1: "AUS", question2: ["item1", "item2"] }],
    hash = data.reduce((hash, o) => {
        Object.entries(o).forEach(([question, value]) => {
            var sub = hash[question] = hash[question] || Object.create(null);
            sub[value] = sub[value] || { question, [value]: 0 };
            sub[value][value]++;
        });
        return hash;
    }, Object.create(null)),
    result = Object.values(hash).reduce((r, sub) => [...r, ...Object.values(sub)], []);

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

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

Comments

1

First, obtain the countries by using reduce. Then use some nested forEach loops for the rest:

const input = [{"question1":"USA","question2":["item1"],"question4":2}, 
{"question1":"USA","question2":["item1"],"question4":3}, 
{"question1":"AUS","question2":["item1","item2"]}];
const countriesOutput = input.reduce((acc, curr) => {
  if (!acc.some(e => e[curr.question1])) {
    acc.push({ question: "question1", [curr.question1]: 1 });
  } else {
    acc.find(e => e[curr.question1])[curr.question1]++;
  }
  return acc;
}, []);
let questionsOutput = [];
input.forEach(item => {
  Object.keys(item).forEach(key => {
    if (key != "question1") {
      if (Array.isArray(item[key])) {
        questionsOutput.push({ question: key, [item[key].join(",")]: 1 });
      } else {
        questionsOutput.push({ question: key, [item[key]]: 1 });
      }
    }
  });
});
const finalOutput = [...countriesOutput, ...questionsOutput];
console.log(finalOutput);
.as-console-wrapper { max-height: 100% !important; top: auto; }

1 Comment

Thanks for the answer, "item1" count should be 2, I was also stucked there
1

Its a matter of summarizing the input using a dictionary (like Object) and track the duplicates. The "name" of the name/value pair can be uniquely identified by combining the question and answer with some delimiter.

const input = [{
    "question1": "USA",
    "question2": ["item1"],
    "question4": 2
  },
  {
    "question1": "USA",
    "question2": ["item1"],
    "question4": 3
  },
  {
    "question1": "AUS",
    "question2": ["item1", "item2"]
  }
];



//Sum the input to an array which we can easily search for duplciates
var repeatCounter = {};

input.forEach(objItem => {

  Object.keys(objItem).forEach(propItem => {


    //Get the counter and the string
    var s = `${propItem}-${objItem[propItem]}`;
    var c = repeatCounter[s] || 0;

    //Modify it or introduce it if absent
    repeatCounter[s] = c + 1;


  })

})




var output = Object.keys(repeatCounter).map(element => {

  var ret = {'question': element.split('-')[0]}

  ret[element.split('-')[1]] = repeatCounter[element];
  
  return ret;

})


   console.log(output);
.as-console-wrapper {
  max-height: 100% !important;
}

Subtle adjustments such as fortifying the delimiter, converting multiple strings in to array items(as shown in the question) needs to be done on practical grounds.

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.