简体   繁体   中英

count all values on object array - javascript

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

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

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM