I have an array of objects like so
[
{_id: "5ca8b8ca0f1b2f54646ded9a", question: "Do you like it?", answer: "yes"},
{_id: "5ca8b8ca0f1b2f54646ded99", question: "Do you like it?", answer: "no"},
{_id: "5ca8b8f80f1b2f54646deda1", question: "Where are you?", answer: "home"},
{_id: "5ca8b8f80f1b2f54646deda0", question: "Where are you?", answer: "home"}
]
and I want it to be reproduced like the following:
[
{
"question": "Do you like it?",
"answers": [{"answer": "yes", "count": 1}, {"answer": "no", "count": 1}]
},
{
"question": "Where are you?",
"answers": [{"answer": "home", "count": 2}]
}
]
I have tried to solve this but i couldn't so any help would be much appreciated. Thank you
We can use Array.find to find the question-answer pair then add a new question-answer pair object if the pair is not existing or update the existing question-answer pair object.
If the question exits but the answer doesn't then simply add the new answer in the answers array.
If both the question and answer exists then increment the answer count property by 1.
If the question itself is missing then add a new object with the question property and answers property and set the count to 1.
Then finally use Array.reduce to accumulate the objects into an array.
const data = [
{_id: "5ca8b8ca0f1b2f54646ded9a", question: "Do you like it ?", answer: "yes"},
{_id: "5ca8b8ca0f1b2f54646ded99", question: "Do you like it ?", answer: "no"},
{_id: "5ca8b8f80f1b2f54646deda1", question: "Where are you ?", answer: "home"},
{_id: "5ca8b8f80f1b2f54646deda0", question: "Where are you ?", answer: "home"}
];
const res = data.reduce((acc, {question, answer}) => {
qFound = acc.find(qa => qa.question === question);
if(qFound){
ansFound = qFound.answers.find(ans => ans.answer === answer);
if(ansFound){
ansFound.count = ansFound.count + 1;
}else{
qFound.answers.push({answer, count:1});
}
}else{
acc.push({
question,
answers: [].concat({answer, count: 1})
});
}
return acc;
},[]);
console.log(res);
use reduce to create objects grouped by question and answer values and then later to discard the keys use Object.values()
const input = [
{_id: "5ca8b8ca0f1b2f54646ded9a", question: "Do you like it ?", answer: "yes"},
{_id: "5ca8b8ca0f1b2f54646ded99", question: "Do you like it ?", answer: "no"},
{_id: "5ca8b8f80f1b2f54646deda1", question: "Where are you ?", answer: "home"},
{_id: "5ca8b8f80f1b2f54646deda0", question: "Where are you ?", answer: "home"}
];
const groupByQuestionAndAnswers = Object.values(input.reduce((accu, {question, answer}) => {
if(!accu[question])
accu[question] = {question};
if(!accu[question][answer])
accu[question][answer] = {answer, count: 0};
accu[question][answer].count += 1;
return accu;
}, {}));
const output = groupByQuestionAndAnswers.map(({question, ...res}) => {
return {question, answers: Object.values(res)};
});
console.log(output);
I'm beginner Javascript student and have to make a trivia game. I have an array of objects which are questions. I want to randomly select an object(question) and then use it, and then get rid of it so that it doesn't get brought up again when I pick the next question. How can I do this correctly? What I have tried so far is:
class Question
{
constructor(t,oA,oB,oC,oD,ans)
{
this.title=t;
this.optionA=oA;
this.optionB=oB;
this.optionC=oC;
this.optionD=oD
this.answer=ans;
}
displayQuestion1R1()
{
userAnswer=prompt(`${this.title}\nA.${this.optionA}\nB.${this.optionB}\nC.${this.optionC}\nD.${this.optionD}`);
}
}
Round1Questions.push(new Question("According to scientists, how old,
approximately, is Earth?", "3 billions years", "100 million years", "4.5
billion years","2.5 billion years", "4.5 billion years"));
Round1Questions.push(new Question("Who was the first American President?",
"Benjamin Franklin", "Barack Obama", "George Washington","Thomas Jefferson",
"George Washington"));
Round1Questions.push(new Question("How many Presidents have there been up to
this year?(2019)?", "45", "40", "60","46", "45"));
Round1Questions.push(new Question("What is the largest Ocean in the world?",
"Atlantic Ocean", "Pacific Ocean", "Indian Ocean","Arctic Ocean", "Pacific
Ocean"));
Round1Questions.push(new Question("Which one of the following is not a
Marvel super-hero?","Spider-Man","Hulk","Batman", "Iron Man", "Batman"));
let ri=RoundQuestions1[Math.floor(Math.random()*Round1Questions.length)];
let question1R1=Round1Questions.splice(ri, 1);
question1R1.displayQuestion1R1();
When I try to run this it says question1R1.displayQuestion1R1() is not a function. However if I remove the splice method I have and just do
let question1R1=RoundQuestions1[Math.floor(Math.random()*Round1Questions.length)];
and then do question1R1.displayQuestion1R1() then it works. However that doesn't allow me to remove the question from the array. How can I accomplish this?
Ok Jack Bashford was close too, but splice method return a array value.
class Question {
constructor(t, oA, oB, oC, oD, ans) {
this.title = t;
this.optionA = oA;
this.optionB = oB;
this.optionC = oC;
this.optionD = oD
this.answer = ans;
}
displayQuestion1R1() {
// userAnswer = prompt(`${this.title}\nA.${this.optionA}\nB.${this.optionB}\nC.${this.optionC}\nD.${this.optionD}`);
console.log( `${this.title}\nA.${this.optionA}\nB.${this.optionB}\nC.${this.optionC}\nD.${this.optionD}` )
}
}
var Round1Questions = [];
Round1Questions.push(new Question("According to scientists, how old, approximately, is Earth ? ",
"3 billions years ", "100 million years ", "4.5 billion years ","2.5 billion years ",
"4.5 billion years ")
);
Round1Questions.push(new Question("Who was the first American President?",
"Benjamin Franklin", "Barack Obama", "George Washington", "Thomas Jefferson",
"George Washington")
);
Round1Questions.push(new Question("How many Presidents have there been up to this year ? (2019) ? ",
"45", "40", "60","46",
"45")
);
Round1Questions.push(new Question("What is the largest Ocean in the world?",
"Atlantic Ocean", "Pacific Ocean", "Indian Ocean", "Arctic Ocean",
"Pacific Ocean ")
);
Round1Questions.push(new Question("Which one of the following is not a Marvel super - hero ? ",
" Spider-Man", "Hulk", "Batman", "Iron Man",
"Batman ")
);
do {
let
PickQuestion_N = Math.floor(Math.random() * Round1Questions.length),
PickedQuestion = Round1Questions.splice(PickQuestion_N, 1)[0]
;
PickedQuestion.displayQuestion1R1();
} while (Round1Questions.length > 0)
Problem
Your approach does not work because of two reasons:
You used RoundQuestions1[Math.floor(Math.random()*Round1Questions.length)] to get your Question instance to assign to r1 variable. Then, you use that instance in Round1Questions.splice(ri, 1), which is not the expected argument type of Array.prototype.splice method.
Round1Questions.splice(ri, 1) returns an Array. So your question1R1 is an array instead of a Question.
Solution
Instead of getting a random Question, try getting a random Quesiton index instead.
Use the random index to splice the Question bank.
Get the first item of the array returned from .splice. See why here.
Working code below (see comments for explanation):
class Question {
constructor(t, oA, oB, oC, oD, ans){
this.title = t;
this.optionA = oA;
this.optionB = oB;
this.optionC = oC;
this.optionD = oD
this.answer = ans;
}
displayQuestion1R1(){
const { title, optionA, optionB, optionC, optionD } = this;
const userAnswer = prompt(`
${title}
A. ${optionA}
B. ${optionB}
C. ${optionC}
D. ${optionD}
`);
}
}
const Round1Questions = [
new Question(
"According to scientists, how old, approximately, is Earth?", "3 billions years",
"100 million years",
"4.5 billion years",
"2.5 billion years",
"4.5 billion years"
),
new Question(
"Who was the first American President?",
"Benjamin Franklin",
"George Washington",
"Thomas Jefferson",
"George Washington"
),
new Question(
"How many Presidents have there been up to this year (2019)?",
"45",
"40",
"60",
"46",
"45"
),
new Question(
"What is the largest Ocean in the world?",
"Atlantic Ocean",
"Pacific Ocean",
"Indian Ocean",
"Arctic Ocean",
"Pacific Ocean"
),
new Question(
"Which one of the following is not a Marvel super-hero?",
"Spider-Man",
"Hulk",
"Batman",
"Iron Man",
"Batman"
)
];
console.log(`Bank before prompt:`, Round1Questions.map(o => o.title));
// Instead of getting the question, get the index of question
let ri = randomQuestionIndex(Round1Questions);
// Use `ri` index to splice your question array.
// Notice the `[0]` to get the first item in the returned array
let question1R1 = Round1Questions.splice(ri, 1)[0];
// No error now because `question1R1` is a `Question` class instance
question1R1.displayQuestion1R1();
console.log(`Bank after prompt:`, Round1Questions.map(o => o.title));
function randomQuestionIndex(bank){
return Math.floor(Math.random() * bank.length);
}
/* NOT RELATED TO YOUR CODE */
/* JUST TO MAKE CONSOLE MORE VISIBLE */
.as-console-wrapper { max-height: 100% !important; }
PS
Don't copy paste any answer here because your professor will immediately find out.
This question already has answers here:
Accessing an object property with a dynamically-computed name
(19 answers)
Closed 7 years ago.
I have the following problem:
I have the following JSON:
var words = {
"categorias": [
{
"Licores": ["Smirnoff", "Johnnie Walker", "Bacardi", "Martini", "Hennessy", "Absolut", "Jack Daniels", "Chivas Regal", " Baileys", "Ballantines", "CAPTAIN MORGAN", "CUERVO", "JAEGERMEISTER", "MOET ET CHANDON", "DEWARS", "JIM BEAM", "GALLO", "HARDYS", "CROWN ROYAL", "RICARD", "CONCHA Y TORO", "GREY GOOSE", "GORDONS", "GRANTS", "JAMESON", "MALIBU", "STOLICHNAYA", "MARTELL", "HAVANA CLUB", "REMY MARTIN", "PATRON", "YELLOWTAIL", "SAUZA", "SKYY", "FINLANDIA", "BERINGER", "TANQUERAY", "DREHER", "BEEFEATER", "BOMBAY", "SEAGRAM", "CANADIAN CLUB", "GLENFIDDICH", "COINTREAU", "TEACHERS", "KAHLUA", "BELLS", "CINZANO VERMOUTH", "LINDEMANS", "COURVOISIER", "CANADIAN MIST", "TORRES", "INGLENOOK", "CASTILLO", "KUMALA", "PENFOLDS", "LANSON", "Ron", "Vodka", "Whisky", "Bourbon", "Brandy", "Cognac", "Tequila", "Ginebra", "Vino blanco", "Vino tinto", "Champagne", "Cerveza", "Budweiser", "Heineken", "Sambuca", "Frangelico", "Triple Sec", "Licor de cafe", "Kirsch", "Fernet", "Aguardiente", "Pisco", "Sangría", "Mojito", "Margarita", "Cuba libre", "Daiquiri", "Cosmopolitan", "Caipirinha", "White Russian", "Coco Loco", "Mai Tai", "Manhattan", "Zombie", "Gintonic", "Hurricane", "Negroni", "Paloma", "Farnell"]
},
{
"animales": ["Abadejo", "Abanto", "Abeja", "Abeja doméstica", "Abejorro", "Abubilla", "Abulón", "Acedía", "Acentor", "Acevia", "Acocil", "Acranio", "Actinia", "Addax", "Agachadiza", "Aguará", "Águila", "Agutí", "Ajolote", "Alacrán", "Albatros", "Alburno", "Alcaraván", "Alcatraz", "Alcaudón", "Alce", "Alcélafo", "Alimoche", "Almeja", "Alondra ibis", "Alosa", "Alpaca", "Alzacola", "Ameba", "Ampelis", "Anaconda", "Anchoa", "Anfioxo", "Angelote", "Anguila", "Aninga", "Anoa", "Anolis", "Ánsar", "Anta", "Antílope", "Araguato", "Araña", "Arapaima", "Arapapa", "Ardilla", "Arenque", "Argonauta", "Armadillo", "Armiño", "Arrendajo", "Asno", "Atún", "Avefría", "Avestruz", "Avispa", "Avetoro", "Avispón", "Avoceta", "Avutarda", "Ayeaye", "Ayu", "Babirusa", "Babosa", "Babuino", "Bacalao", "Baiji"]
}
]
}
So when I want search a Categoria I call this function:
function random(max){
return Math.floor((Math.random() * max) + 0);
}
Now as the Key of JSON is a array (categorias), and this key i want get of way random, then i use Object.keys(), and it runs smoothly, when i assigned the var namKeyJson to Object.keys(words.categorias[randomCategory]), i returned the name of the key which i need
var lengthCategory = words.categorias.length-1;
var randomCategory = random(lengthCategory);
var nameKeyJson = Object.keys(words.categorias[randomCategory]);
nameKeyJson = nameKeyJson.toString();
the problem is when i want get the values or the length the categorys of array, and that by placing the variable nameKeyJson, takes the name of the variable but not its value.
var lengthPregunta = words.categorias[randomCategory].nameKeyJson.length;
console.log(lengthPregunta);
Thanks for help me.
var lengthPregunta = words.categorias[randomCategory].nameKeyJson.length;
Should be
var lengthPregunta = words.categorias[randomCategory][nameKeyJson].length;
You try to call 'nameKeyJson' from words.categorias[randomCategory] instead of indexing key by nameKeyJson.
Use bracket notations:
words.categorias[randomCategory][nameKeyJson]
and with your code it will always return only first variable.
So change
var lengthCategory = words.categorias.length-1; to
var lengthCategory = words.categorias.length;
var words = {
"categorias": [{
"Licores": ["Smirnoff", "Johnnie Walker", "Bacardi", "Martini", "Hennessy", "Absolut", "Jack Daniels", "Chivas Regal", " Baileys", "Ballantines", "CAPTAIN MORGAN", "CUERVO", "JAEGERMEISTER", "MOET ET CHANDON", "DEWARS", "JIM BEAM", "GALLO", "HARDYS", "CROWN ROYAL", "RICARD", "CONCHA Y TORO", "GREY GOOSE", "GORDONS", "GRANTS", "JAMESON", "MALIBU", "STOLICHNAYA", "MARTELL", "HAVANA CLUB", "REMY MARTIN", "PATRON", "YELLOWTAIL", "SAUZA", "SKYY", "FINLANDIA", "BERINGER", "TANQUERAY", "DREHER", "BEEFEATER", "BOMBAY", "SEAGRAM", "CANADIAN CLUB", "GLENFIDDICH", "COINTREAU", "TEACHERS", "KAHLUA", "BELLS", "CINZANO VERMOUTH", "LINDEMANS", "COURVOISIER", "CANADIAN MIST", "TORRES", "INGLENOOK", "CASTILLO", "KUMALA", "PENFOLDS", "LANSON", "Ron", "Vodka", "Whisky", "Bourbon", "Brandy", "Cognac", "Tequila", "Ginebra", "Vino blanco", "Vino tinto", "Champagne", "Cerveza", "Budweiser", "Heineken", "Sambuca", "Frangelico", "Triple Sec", "Licor de cafe", "Kirsch", "Fernet", "Aguardiente", "Pisco", "Sangría", "Mojito", "Margarita", "Cuba libre", "Daiquiri", "Cosmopolitan", "Caipirinha", "White Russian", "Coco Loco", "Mai Tai", "Manhattan", "Zombie", "Gintonic", "Hurricane", "Negroni", "Paloma", "Farnell"]
}, {
"animales": ["Abadejo", "Abanto", "Abeja", "Abeja doméstica", "Abejorro", "Abubilla", "Abulón", "Acedía", "Acentor", "Acevia", "Acocil", "Acranio", "Actinia", "Addax", "Agachadiza", "Aguará", "Águila", "Agutí", "Ajolote", "Alacrán", "Albatros", "Alburno", "Alcaraván", "Alcatraz", "Alcaudón", "Alce", "Alcélafo", "Alimoche", "Almeja", "Alondra ibis", "Alosa", "Alpaca", "Alzacola", "Ameba", "Ampelis", "Anaconda", "Anchoa", "Anfioxo", "Angelote", "Anguila", "Aninga", "Anoa", "Anolis", "Ánsar", "Anta", "Antílope", "Araguato", "Araña", "Arapaima", "Arapapa", "Ardilla", "Arenque", "Argonauta", "Armadillo", "Armiño", "Arrendajo", "Asno", "Atún", "Avefría", "Avestruz", "Avispa", "Avetoro", "Avispón", "Avoceta", "Avutarda", "Ayeaye", "Ayu", "Babirusa", "Babosa", "Babuino", "Bacalao", "Baiji"]
}]
}
function random(max) {
return Math.floor((Math.random() * max) + 0);
}
var lengthCategory = words.categorias.length;
var randomCategory = random(lengthCategory);
var nameKeyJson = Object.keys(words.categorias[randomCategory]);
var lengthPregunta = words.categorias[randomCategory][nameKeyJson].length;
console.log(lengthPregunta);