I am trying to make a simple multiple choice-like quiz using data from an array, but I am getting an error: TypeError: Cannot read property '0' of undefined.
The possible choices should be 4, with the correct answer being the first choice. I have tried searching online for solutions, but I do not know what is causing the error and how to fix it:
var masterlist = [
["Indonesia", "Jakarta"],
["Malaysia", "Kuala Lumpur"],
["Philippines", "Manila"],
["Singapore", "Singapore"],
["Thailand", "Bangkok"],
["Vietnam", "Hanoi"]
];
function randomNoRepeats(array) {
var copy = array.slice(0);
return function() {
if (copy.length < 1) {
copy = array.slice(0);
}
var index = Math.floor(Math.random() * copy.length);
var item = copy[index];
copy.splice(index, 1);
return item;
};
}
var chooser = randomNoRepeats(masterlist); //randomize choices
//console.log(chooser());
var quizArea = document.getElementById("test-area");
var a = []; // new empty array to store randomized items
var c = []; // new empty array to store randomized items (copy)
var b;
var correctAnswer;
for (var i = 0; i < masterlist.length; i++) {
b = chooser();
a.push(b);
}
c = a;
//console.log("a", a, a.length); // ERROR here; expected an array length of 6
for (var i = 0; i < masterlist.length; i++) {
correctAnswer = c[i];
var index = a.indexOf(correctAnswer); // remove correct answer from list of other/wrong choices
a.splice(index, 1);
var otherChoices = a.slice(0, 3); // choose only 3 wrong/other choices
var question = document.createElement("p");
question.innerHTML = "What is the capital of " + correctAnswer[0] + "?"; // ERROR
var answers = document.createElement("p");
answers.innerHTML = correctAnswer[1] + ", " + otherChoices[0][1] + ", " + otherChoices[1][1] + ", " + otherChoices[2][1]; // place correct answer at index 0; TypeError: Cannot read property '0' of undefined
quizArea.appendChild(question);
quizArea.appendChild(answers);
}
<div id="test-area"></div>
The issue comes from the statement c = a;. It does not copy the array. Both c and a reference the same array object.
This means that the line a.splice(index, 1) changes a AND c in place.
One solution here is to use a real copy of a in your last for loop.
for (var i = 0; i < masterlist.length; i++) {
c = a.slice(0); // or c = [...a];
// use `c` here
}
var masterlist = [
["Indonesia", "Jakarta"],
["Malaysia", "Kuala Lumpur"],
["Philippines", "Manila"],
["Singapore", "Singapore"],
["Thailand", "Bangkok"],
["Vietnam", "Hanoi"]
];
function randomNoRepeats(array) {
var copy = array.slice(0);
return function() {
if (copy.length < 1) {
copy = array.slice(0);
}
var index = Math.floor(Math.random() * copy.length);
var item = copy[index];
copy.splice(index, 1);
return item;
};
}
var chooser = randomNoRepeats(masterlist); //randomize choices
//console.log(chooser());
var quizArea = document.getElementById("test-area");
var a = []; // new empty array to store randomized items
var c;
var b;
var correctAnswer;
for (var i = 0; i < masterlist.length; i++) {
b = chooser();
a.push(b);
}
//console.log("a", a, a.length); // ERROR here; expected an array length of 6
for (var i = 0; i < masterlist.length; i++) {
c = a.slice(0);
correctAnswer = c[i];
var index = c.indexOf(correctAnswer); // remove correct answer from list of other/wrong choices
c.splice(index, 1);
var otherChoices = c.slice(0, 3); // choose only 3 wrong/other choices
var question = document.createElement("p");
question.innerHTML = "What is the capital of " + correctAnswer[0] + "?"; // ERROR
var answers = document.createElement("p");
answers.innerHTML = correctAnswer[1] + ", " + otherChoices[0][1] + ", " + otherChoices[1][1] + ", " + otherChoices[2][1]; // place correct answer at index 0; TypeError: Cannot read property '0' of undefined
quizArea.appendChild(question);
quizArea.appendChild(answers);
}
<div id="test-area"></div>
Related
I am developing a Rubik cube app for fitbit versa and I run into the problem of removing duplicates from arrays as I get a NaN error when combining the arrays once the duplicates have been removed from the end of the list and it only happens when I splice at the end of the array and I cant figure out the reason why this isnt working
function getScramble(number_of_moves, faces, modifiers, scramble_faces, scramble_modifiers, scramble) {
for (var i = 0; i < number_of_moves; i++) {
var sample = faces[Math.floor(Math.random() * faces.length)];
var mod = modifiers[Math.floor(Math.random() * modifiers.length)];
scramble_faces[i] = sample;
scramble_modifiers[i] = mod;
if (scramble_faces[i] == scramble_faces[i - 1]) {
scramble_faces[i] = faces[Math.floor(Math.random() * faces.length)];
}
}
removeDuplicates(scramble_faces, scramble_modifiers)
for (var i = 0; i < number_of_moves - 2; i++) {
scramble[i] = scramble_faces[i] + scramble_modifiers[i]
}
console.log(scramble);
let demotext = document.getElementById("demotext");
demotext.text = scramble;
scramble = [];
scramble_faces = [];
scramble_modifiers = [];
}
function threebythree() {
var faces = ["U", "D", "L", "R", "F", "B"];
var modifiers = ["", "'", "2"];
var scramble_faces = [];
var scramble_modifiers = [];
var scramble = [];
var number_of_moves = 22;
let Title1 = document.getElementById("title");
Title1.text = "3x3"
getScramble(number_of_moves, faces, modifiers, scramble_faces, scramble_modifiers, scramble, Title1)
}
function removeDuplicates(arr, arr2, number_of_moves) {
var t = 0;
var new_arr = arr;
var new_arr2 = arr2;
for (var i = new_arr.length - 1; i >= 0; i--) {
if (new_arr[i] === new_arr[i - 1]) {
new_arr.splice(i, 1);
new_arr2.splice(i, 1);
}
}
arr = new_arr;
arr2 = new_arr2;
new_arr = [];
new_arr2 = [];
new_arr.pop();
new_arr2.pop();
console.log(arr);
console.log(arr2);
}
The lengths of scramble_faces and scramble_modifiers is initially number_of_moves. But after you remove duplicates from them, it can be shorter. But you still use number_of_moves in the limit in the next for loop. So when you try to add the elements that no longer exist you get undefined. undefined + undefined == NaN.
You should use the length of one of the arrays instead:
function getScramble(number_of_moves, faces, modifiers, scramble_faces, scramble_modifiers, scramble) {
for (var i = 0; i < number_of_moves; i++) {
var sample = faces[Math.floor(Math.random() * faces.length)];
var mod = modifiers[Math.floor(Math.random() * modifiers.length)];
scramble_faces[i] = sample;
scramble_modifiers[i] = mod;
if (scramble_faces[i] == scramble_faces[i - 1]) {
scramble_faces[i] = faces[Math.floor(Math.random() * faces.length)];
}
}
removeDuplicates(scramble_faces, scramble_modifiers)
for (var i = 0; i < scramble_faces.length - 2; i++) {
scramble[i] = scramble_faces[i] + scramble_modifiers[i]
}
console.log(scramble);
let demotext = document.getElementById("demotext");
demotext.text = scramble;
scramble = [];
scramble_faces = [];
scramble_modifiers = [];
}
I have a random generator from 1 to 10 that produces non repeating values
I am trying to get the previous value.
So if current is 5 and then 8
Previous 8 and next is 9, etc
This is my code:
var randomNumbers = [];
var numRandoms = 11;
var myVar = setInterval(randomUnique1to10, 5000);
function randomUnique1to10() {
// refill the array if needed
if (!randomNumbers.length) {
for (var i = 1; i < numRandoms; i++) {
randomNumbers.push(i);
}
}
var index = Math.floor(Math.random() * randomNumbers.length);
var val = randomNumbers[index];
if (i === 1) { // i would become 0
i = randomNumbers.length; // so put it at the other end of the array
}
i = i - 1; // decrease by one
previous = randomNumbers[i]; // give us back the item of where we are now
randomNumbers.splice(index, 1);
Thank you
This is totally what you're looking for. Hope it helps!.
var randomNumbers = [];
var numRandoms = 11;
var myVar = setInterval(randomUnique1to10, 1000);
shuffle = function(o){
for(var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
return o;
};
var finalArray = shuffle([1, 2, 3, 4,5,6,7,8,9,10]);
function randomUnique1to10() {
// refill the array if needed
if (!randomNumbers.length) {
for (var i = 1, l = 11; i < l; i++) { }
}
// var finalArray = shuffle(randomNumbers);
document.write(finalArray + "<br/>");
randomNumbers = finalArray;
var index = Math.floor(Math.random() * randomNumbers.length);
var val = randomNumbers[index];
if (i === 1) { // i would become 0
i = randomNumbers.length; // so put it at the other end of the array
}
x = index-1; // decrease by one
current = randomNumbers[randomNumbers.length - 1]; // give us back the item of where we are now
previous = randomNumbers[randomNumbers.length - 2];
if(previous === undefined)
{
previous = "n/a";
}
randomNumbers.pop();
if(randomNumbers.length <= 0){
finalArray = shuffle([1, 2, 3, 4,5,6,7,8,9,10]);
}
document.write("Current >> " + current + " and previous = " +previous + "<br/>")
}
try this:
var randomNumbers = [];
var numRandoms = 11;
var myVar = setInterval(randomUnique1to10, 5000);
var x;
function randomUnique1to10() {
// refill the array if needed
if (!randomNumbers.length) {
for (var i = 1; i < numRandoms; i++) {
randomNumbers.push(i);
}
}
var index = Math.floor(Math.random() * randomNumbers.length);
var val = randomNumbers[index];
if (i === 1) { // i would become 0
i = randomNumbers.length; // so put it at the other end of the array
}
x = index-1; // decrease by one
previous = randomNumbers[x]; // give us back the item of where we are now
var res = randomNumbers.splice(index, 1);
console.log("result: "+res);
console.log("prev : "+previous);
console.log("Rand : "+randomNumbers);
}
NOTE:
this code have, one problem, if res = min(array) then prev will become unidentify
The question lack a bit of clarity. From the question what I understood is,
The values in the array are non repeating
You have a value at variable current and you want to find the previous value of the current which is stored in the array
And I will answer from what I understood. Using indexOf() gives you the index of current element from the array and you just need to subtract 1 from it to get the previous.
var array = [1, 9, 2, 8, 3, 7, 4, 6, 5];
var current = 8;
var currentIndex = array.indexOf(current);
var previous = currentIndex !== 0 ? array[currentIndex-1] : 'N/A';
document.write('Previous Value: ', previous)
I have an array of 'users' that gets data added/deleted to it. I also have an object 'temp' that will generate a methods based on how many indexes are in the array.
Here's the code I have so far:
var users = [1, 2];
var index = users.length;
var temp = {};
function newTemp(object){
var index = users[object]; //assigns an index #
if(index === undefined){
index = users.length;
users[object] = index;
}
users[index] = object;
for (var i = 0; i < users.length - 1; i++){
temp.['check' + i] = function(){console.log('checking ' + i);}
}
}
newTemp(index);
Ideally, based on how much data is in 'users' I would like 'temp' to contain something like this:
var temp = {
check0 : function(){
console.log('checking ' + 0);
},
check1 : function(){
console.log('checking ' + 1);
}
}
I'm stuck of finding a way to consolidate array elements.
so my array is in format of [id1:port1,id2:port2,id1:port3,id2:port4,id5:port5...] where each element has 2 portions. The id portion is not unique. what I try to consolidate is to create a new array will have data like [id1#port1:port3,id2#port2:port4,id5#port5]
I tried code below but it didn't get me too far. can any guru help me out?
var orinString = "id1:port1,id2:port2,id1:port3,id2:port4,id5:port5";
var newArray1 = orinString.split(",");
var newArray2 = orinString.split(",");
var newArray3 = [];
for (x=0; x<=newArray1.length-1; x++) {
for (y=0; y<= newArray2.length-1; y++) {
if ((newArray1[x].split(":")[0] == newArray2[y].split(":")[0]) && (newArray1[x].split(":")[1] != newArray2[y].split(":")[1])) {
newArray3.push(newArray1[x].split(":")[0] +"#"+ newArray1[x].split(":")[1]);
}
}
}
for (z=0; z<=newArray3.length; z++) {
gs.log("show me the result " +newArray3[z]);
}
is it that you want:
var orinString = "id1:port1,id2:port2,id1:port3,id2:port4,id5:port5";
var arr1 = orinString.split(",");
var temp= "";
var newStr = "";
arr1.sort();
for(i=0; i< arr1.length; i++) {
var item = arr1[i].split(':');
if(item[0] !== temp || temp === "") {
newStr += "," + item[0] + "#" + item[1];
} else {
newStr += ":"+item[1];
}
temp = item[0];
}
console.log(newStr.substring(1));
A typical way to solve a problem like this is
Convert them into workable values
Populate some kind of lookup table
Output the results of this lookup table
For example
var orinString = "id1:port1,id2:port2,id1:port3,id2:port4,id5:port5";
var idsAndPorts = orinString.split(",");
// Populate a key lookup
var hashTable = {};
idsAndPorts.forEach(function(s) {
var splitValue = s.split(':');
var key = splitValue[0];
var value = splitValue[1];
if(hashTable[key]) {
hashTable[key].push(value);
} else {
hashTable[key] = [value];
}
});
// Now convert it back into an array again
var finalArray = [];
for(var k in hashTable) {
finalArray.push(k + '#' + hashTable[k].join(','));
}
// View the results
finalArray.forEach(function(f) {
console.log(f);
})
This does not guarantee the final array will be sorted, but you can sort it yourself if you wish.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 8 years ago.
Improve this question
I have an array
var arr = ["2:6", "2:3", "1:1", "1:2", "3:1"];
(This is javascript);
I don't know how to convert this array into output:
["2:6,3", "1:1,2", "3:1"];
May be you can help me?
It looks like you want to group together the elements of the list who have the same initial digit. This code will give you the associative array {"1":"1,2","2":"6,3","3ยง:"1"} as an output:
var arr = ["2:6", "2:3", "1:1", "1:2", "3:1"];
var hist = {};
arr.map( function (a) { b=a.split(":");c=b[0]; if (c in hist) hist[c]=hist[c].concat(","+b[1]); else hist[c] = b[1]; } );
alert(JSON.stringify(hist));
See also JavaScript Group By Array
var interm = {}, output = [], regx = /(\d+):(\d+)/;
arr.forEach(function(x) {var y = regx.exec(x); if (y[1] in interm) interm[y[1]].push(y[2]); else interm[y[1]] = [y[2]]});
Object.keys(interm).map(function(x) { output.push(x + ":" + interm[x].join(',')) });
console.log(output);
[ '1:1,2', '2:6,3', '3:1' ]
That's far from the most efficient conversion in terms of speed as it uses regex and forEach, but it's fairly concise and you didn't mention that you needed anything particularly quick.
Please see this LINK..
or apply below code...
HTML Code...
<input type='button' id='s' value='test' onclick="test()"/>
JQuery code...
function test() {
var arr = ["2:6", "2:3", "1:1", "1:2", "3:1"];
var resultStr = "";
for (i = 0; i < arr.length; i++) {
if (i <= arr.length - 2) {
var a = arr[i + 1].split(":");
if (a.length > 0) {
resultStr += arr[i] + ',' + a[1] + ' | ';
}
} else {
var str = arr[i];
resultStr += arr[i];
}
i++;
}
alert(resultStr);
}
Here is an working example on JSFiddle
And the sample code below,
var arr = ["2:6", "2:3", "1:1", "1:2", "3:1"];
var tdarray = {};
var newarray = [];
for(var i=0;i<arr.length;i++){
var data = arr[i].split(":");
var found = false;
for(var key in tdarray){
if(data[0]==key){
found = true;
break;
}
}
var list=[];
if(found){
list = tdarray[data[0]];
}
list.push(data[1]);
tdarray[data[0]] = list;
}
for(key in tdarray){
var data = key + ":" + tdarray[key].join();
newarray.push(data);
}
console.log(newarray);
And another possible solution...
var arr = ["2:6", "2:3", "1:1", "1:2", "3:1"], alreadyUsedNumbers = [];
for (var i=0; i < arr.length; i++) {
var key = arr[i].split(":")[0], value = arr[i].split(":")[1];
if (alreadyUsedNumbers.indexOf(key) >= 0) {
for (var j=0; j < i; j++) {
if (arr[j].indexOf(key) == 0) {
arr[j] += ","+value;
arr.splice(i, 1)
i--;
break;
}
}
} else {
alreadyUsedNumbers.push(key);
}
}
console.log(arr);
... enjoy.
var arr = ["2:6", "2:3", "1:1", "1:2", "3:1", "4:6", "3:4"];
var output = new Array();
var outputString = "[";
for(var i=0; i<arr.length; i++)
{
var index = arr[i].indexOf(":");
var firstNr = arr[i].substring(0,index);
var secondNr = arr[i].substring(index+1,arr[i].length);
var outputPart = firstNr + ":" + secondNr;
var j = i+1;
while (j<arr.length)
{
var index2 = arr[j].indexOf(":");
var firstNr2 = arr[j].substring(0,index2);
var secondNr2 = arr[j].substring(index2+1,arr[j].length);
if (firstNr == firstNr2)
{
outputPart += "," + secondNr2;
arr.splice(j,1);
}
else
j++;
}
output.push(outputPart);
}
for(var k=0; k<output.length; k++)
outputString += "'" + output[k] + "' ";
outputString += "]";
alert(outputString);
Demo here: http://jsfiddle.net/er144/QYca2/
Your output looks a lot like a map. I would write it as:
{
2 : [ 6, 3 ],
1 : [ 1, 2 ],
3 : [ 1 ]
}
To get that map, i would iterate over the array, extracting the key and value and then adding the value to the correct array, making sure to create it if it hasn't been created already.
var arr = ["2:6", "2:3", "1:1", "1:2", "3:1"];
var map = {};
arr.forEach(function(item){
var split = item.split(':');
if (!map[split[0]]) map[split[0]] = [split[1]];
else map[split[0]].push(split[1]);
});
Obviously from my map you can get your desired array quite easily:
var result = [];
for (var key in map) {
if (map.hasOwnProperty(key)) // best practice
result.push(key+':'+map[key]);
}
console.log(result); // ["1:1,2", "2:6,3", "3:1"]
One note: it doesn't have the items in the same order you do, but that can easily be fixed by iterating over the original array to get the keys instead of using for..in:
var result = [];
arr.forEach(function(item){
var key = item.split(':')[0];
if (map[key]) {
result.push(key+':'+map[key]);
delete map[key]; // destroys the map!
}
});
console.log(result); // ["2:6,3", "1:1,2", "3:1"]
Solution 2 (no intermediate map):
This solution has O(n^2) complexity:
var arr = ["2:6", "2:3", "1:1", "1:2", "3:1"];
var result = [];
for (var i=0; i<arr.length; i++) {
if (!arr[i]) continue;
var key = arr[i].split(':')[0];
var values = [];
for (var j=i; j<arr.length; j++) {
var split = arr[j].split(':');
if (split[0] === key) {
values.push(split[1]);
arr[j] = undefined; // destroys the original array
}
}
result.push(key + ':' + values);
}
console.log(result); // ["2:6,3", "1:1,2", "3:1"]