Today I (tried) created some code to create mcq questions.
The code is supposed to generate a random codon, find its amino acid from the codon table/chart and display it on the document along with other (3) random wrong options.
I want to make a mcq with 4 options (1 is correct rest are wrong).
What I am trying to do below is: The computer will form a random sequence of 3 nucleotides (i.e.digits) using form() function. Variable formed will store a codon (eg. UCA, ACC etc.) which will be the question.
Now I declared array arr which will store the correct answer at 0th position.
Then I created a function generateWrongOptions() which will (is supposed to) add the other 3 dissimilar wrong answers to the array. What I tried to do here is that the function will declare a new amino acid (eg. Phe, Ile, Met etc.) which is stored as wrong and a new empty array arr2. The next loop is supposed to check if wrong is already present in arr or not; if it is not then it will push an element 'a' ('a' here doesn't has any meaning) in arr2, if it is then it won't. Now if will check if the arr length is equal to arr2 which simply means if the variable wrong is unique or not (or is duplicate).
I wanted to create 4 options (1 was already present) hence I looped the code for i<3 times.
I found better ways to do this same task online, but those were more advanced and I couldn't understand them. Hence I'd come with my own solution (best I could've guessed).
const obj = {
UUU:"Phe",
UUC:"Phe",
UUA:"Leu",
UUG:"Leu",
CUU:"Leu",
CUC:"Leu",
CUA:"Leu",
CUG:"Leu",
AUU:"Ile",
AUC:"Ile",
AUA:"Ile",
AUG:"Met",
GUU:"Val",
GUC:"Val",
GUA:"Val",
GUG:"Val",
/* - */
UCU:"Ser",
UCC:"Ser",
UCA:"Ser",
UCG:"Ser",
CCU:"Pro",
CCC:"Pro",
CCA:"Pro",
CCG:"Pro",
ACU:"Thr",
ACC:"Thr",
ACA:"Thr",
ACG:"Thr",
GCU:"Ala",
GCC:"Ala",
GCA:"Ala",
GCG:"Ala",
/* - */
UAU:"Tyr",
UAC:"Tyr",
UAA:"Stop",
UAG:"Stop",
CAU:"His",
CAC:"His",
CAA:"Gln",
CAG:"Gln",
AAU:"Asn",
AAC:"Asn",
AAA:"Lys",
AAG:"Lys",
GAU:"Asp",
GAC:"Asp",
GAA:"Glu",
GAG:"Glu",
/* - */
UGU:"Cys",
UGC:"Cys",
UGA:"Stop",
UGG:"trp",
CGU:"Arg",
CGC:"Arg",
CGA:"Arg",
CGG:"Arg",
AGU:"Ser",
AGC:"Ser",
AGA:"Arg",
AGG:"Arg",
GGU:"Gly",
GGC:"Gly",
GGA:"Gly",
GGG:"Gly",
};
const digit = ['U', 'C', 'A', 'G'];
function x() {
return Math.floor(Math.random()*4);
};
function form() {
return digit[x()]+digit[x()]+digit[x()]
}
let formed = form();
let arr = [obj[formed]];
function generateWrongOptions() {
for (i = 0; i < 4; i++) {
let wrong = obj[form()];
let arr2 = [];
for (i = 0; i < arr.length; i++) {
if (wrong!==arr[i]){
arr2.push('a');
};
if(arr2.length==arr.length){
arr.push(wrong)
}
else {
generateWrongOptions()
};
};
};
};
generateWrongOptions();
for (let n of arr) {
console.log(n)
}
Console returns Maximum calls exceeded;
On the other hand a similar code I wrote before creating this - as a guideline - to form an array of 4 different numbers works:
function x() {
return Math.floor(Math.random()*10)
}
let y = x();
let arr = [y];
function aa() {
for (i = 0; i < 4; i++) {
let z = x()
let arr2 = []
for (i = 0; i < arr.length ; i++)
{
if (z!==arr[i])
{arr2.push('a')};
}
if (arr2.length==arr.length)
{arr.push(z)}
else {aa()}
};
};
aa();
console.log(arr);
I think I can fix this code by declaring a new array of all the amino acids in the codon table (obj), but still want to know why the first code doesn't work while the latter does.
I'm not so sure if I understand your code correctly. However, I can see that you have two for loops in which you forgot to create a new variable:
you used "for (i .... )" , and you forgot to say "for (let i ..... )". Another issue i noticed is the redeclaration of "arr" in the last function, which I found weird since you already declared it outside of the function scope. In addition, there is an "arr2" that was also not declared with "let" or "var" words.
Related
I am trying to make it so that when I run the function it checks if there is a save already. If there isn't, then it puts those values in the list. I am using nested arrays and there will be three total saves. But for some reason when I run it, it says that allSaves[L] is undefined. But when I put a zero in for the L, it works. But I can't do that. So does anyone know how I could fix that? Here is my code -
function savingList(principal, interestRate, time, compoundNumber) {
var allSaves = new Array();
allSaves[0] = new Array();
for(var L = 0; L < 2; L++) {
if(allSaves[L].length == 0){
allSaves[L] = new Array(principal, interestRate, time, compoundNumber);
}
}
}
I would suggest creating allSaves directly as an Array.map() instead of using a traditional loop block. Also note that your iterator variable L should be a let instead of a var so that it is scoped appropriately.
function savingList(principal, interestRate, time, compoundNumber) {
return [...new Array(3)].map(saveIteration =>
[principal, interestRate, time, compoundNumber]
)
The phrase [...new Array(i)] is just a way of getting a map-able array of length i.
Question: Develop an array of 1000 objects (having properties name and number as shown).
We need a function to convert every object so the name is uppercased
and values are 5 times the original and store into the higher
variable. Similarly, another function that converts every object so
the name is lower case and value is 3 times the original, store this
into the little variable.
We need a function that takes each object in higher and finds all
objects in little that evenly divide into it. Example: 30 in
higher object is evenly divided by 6 in little.
The output of 2 must be an array of higher numbers, and in every
object there should be got (which is a variable inside the object) which will contain every little
object that evenly divided the higher.
My code:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<script>
var n = 1000;
var sample = [];
for (var i = 0; i < n; i++) sample.push({
name:'John' + i,
value: i
});
console.log(sample);
function Converter() {
var n = 1000;
var higher = sample;
for (var i = 0; i < n; i++) higher.name = 'John' + i;
higher.value = i * 5;
console.log(higher);
}
</script>
</body>
</html>
The array of objects is created and it is as expected/required by the question, however, the converter function for higher does not work, also how should the 3rd question be done?
Some thoughts:
1) only constructors should start with a capital letter, functions should be camelcase by convention so it should be converter
2) you don't call converter() so it never gets executed
3) make sure to indent your code properly var n and var sample should be at the same depth.
4) if you omit the brackets after an if or for, only the following statement gets inside the branch, so in your case you do:
for (var i = 0; i < n; i++)
higher.name = 'John'+i;
higher.value = i*5;
so the second line isn't even executed in the loop, you want:
for (var i = 0; i < n; i++) {
higher.name = 'John'+i;
higher.value = i*5;
}
5) higher.name makes little sense as higher is an array, you want to change the name of the ith higher number which you can do with higher[i].name
6) "John1" is not in caps, you want to call toUpperCase on it (("John1").toUpperCase())
also how should the 3rd question be done?
I guess fixing your code and doing the second question is enough for today.
You could continue reading:
Coding style matters
js array iterations
You should also try to think in a more structured manner about your code here. I would suggest writing separate functions for each problem and giving them meaningful names. Perhaps something like the following:
var n = 1000;
var sample = [];
for (var i = 0; i < n; i++) sample.push({
name: 'John' + i,
value: i
});
console.log(sample);
var higher = convertToHigher(sample);
var little = convertToLittle(sample);
var higherWithDivisors = findAllDivisors(higher, little);
function convertToHigher(arr) {
var newArr = [];
// TODO: iterate through each entry in arr, create a new modified object
// with a higher value and add it to newArr
return newArr;
}
function convertToLittle(arr) {
var newArr = [];
// TODO: iterate through each entry in arr, create a new modified object
// with a lower value and add it to newArr
return newArr;
}
function findAllDivisors(arr1, arr2) {
var newArr = [];
// TODO: solve problem 3 here
return newArr;
}
The process: In the game I'm making, there's a for loop that's supposed to save a value in an array. That value changes with each iteration. The problem: when the loop is done running, every element of the array is identical, all showing the most recent value.
I know this issue is common, and I've made so many different tweaks and attempts at solving it over the past 2 days.
0) I tried separating things into separate functions as much as possible.
1) I tried defining my loop counters with "let" so they would have a local scope.
2) I tried wrapping my assignment in a self-executing function so it would happen immediately, preserving the value of currentlyOn before the next loop iteration changes it. My counter is the variable c.
(function(c2, currentlyOn2) {
onAtSameTime[c2] = currentlyOn2;
return 0;
})(c, currentlyOn);
3) I tried attempt #2 with the added feature of returning a function, which still didn't save the value of currentlyOn. This option isn't a good one for me anyway, because the whole point is that I'm doing some computations ahead of time so my game will have a quick animation loop.
onAtSameTime[c] = (function(currentlyOn2) {
return function() {
return currentlyOn2;
};
})(currentlyOn);
I'm tired of beating my head against this wall. Can anyone explain what I'm doing wrong?
For more details, check out the jsfiddle I made. The problem area is at line 59, using a simple assignment:
onAtSameTime[c] = currentlyOn;
onAtSameTime[c] = currentlyOn; sets onAtSameTime[c] equal to the reference of currentlyOn, since currentlyOn is an array, not a primitive value. That reference gets updated with each iteration. You could work around that by creating a copy of the array before adding it to the onAtSameTime array. Something like onAtSameTime[c] = [].concat(currentlyOn); would do the trick.
See this fork of your JSFiddle: https://jsfiddle.net/L2by787y/
You could make a copy from currentlyOn for assigning to onAtSameTime[c]. This keeps the values, but does not keep the reference to the same array.
onAtSameTime[c] = currentlyOn.slice(); // use copy
"use strict";
function log(text) {
document.getElementById("logbox").innerHTML += JSON.stringify(text) + "<br>";
return 0;
}
function whichSwitchesAreOn() {
var currentlyOn = [],
flickedSet,
flickedOne,
turningOnCheck;
for (var c = 0; c < switchesToggled.length; c++) {
flickedSet = switchesToggled[c];
for (var d = 0; d < flickedSet.length; d++) {
flickedOne = flickedSet[d];
turningOnCheck = currentlyOn.indexOf(flickedOne);
if (turningOnCheck == -1) {
currentlyOn.push(flickedOne);
} else {
currentlyOn.splice(turningOnCheck, 1);
}
}
log("currentlyOn: " + currentlyOn);
onAtSameTime[c] = currentlyOn.slice(); // use copy
}
return 0;
}
var switchesToggled = [[0], [1, 2], [0], [2], []],
onAtSameTime = [];
whichSwitchesAreOn();
log(onAtSameTime);
<div id="logbox"></div>
You say you have tried let?
Did you have let currentlyOn = [] inside of the for loop?
for(var c = 0; c < switchesToggled.length; c++) {
let currentlyOn = [];
I am trying to make two arrays. the unique array can get the elements (no repeats) from the text array, and the counter one can count the frequency of each elements. but something is wrong with the counter one.
var unique_array=new Array();
var counter_array=new Array();
var unique=true;
for (i=0;i<text_array.length;i++){
if (unique_array.length==0){
unique_array.push(text_array[0]);
counter_array.push(1);
}
else if(unique_array.length>0&&unique_array.length<=text_array.length){
for (j=0; j<unique_array.length;j++){
if (text_array[i]==unique_array[j]){
counter_array[j]=counter_array[j]+1;// something wrong with the
alert(counter_array[j]);
var unique=false;
}
}
if (unique==true){
unique_array.push(text_array[i]);
counter_array.push[1];
}
unique=true;
}
You could also simplify the code down using a hashmap and some ES5 higher-order functions:
var text_array = ["a1","a1","a2","a3","a2","a4","a1","a5"];
var counts = {};
text_array.forEach(function(el) {
counts[el] = counts.hasOwnProperty(el) ? counts[el]+1 : 1;
});
var unique_array = Object.keys(counts);
var counter_array=unique_array.map(function(key) { return counts[key]; })
You can do this much more simply using an object. Let the values be the keys of an object, then just increment the count of each property as you go. At the end, you can get an array of the unique keys and their values:
var text_array = ['foo','bar','foo','fum','fum','foo'];
var i = text_array.length;
var obj = {};
while (i--) {
if (obj.hasOwnProperty(text_array[i])) {
obj[text_array[i]]++;
} else {
obj[text_array[i]] = 1;
}
}
console.log('Unique values: ' + Object.keys(obj)); // Unique values: foo,fum,bar
console.log('Value counts: ' + Object.keys(obj).map(function(v){return obj[v]})); // Value counts: 3,2,1
Note that the sorting of counts in the output is purely coincidental.
As Jasvir posted, you can make it pretty concise:
var obj = {};
text_array.forEach(function(v) {
obj.hasOwnProperty(v)? ++obj[v] : obj[v] = 1;
});
But the first example is a bit easier to digest.
I think the approach is what's making it difficult. A hash table / associative array would be much easier to work with.
With a hash table (an object {} in JS), you can store each word in a key and increment the value of the key when you encounter the word again. Then, at the end, just go through the hash table and gather up all the keys which have small values. Those are your unique words.
function get_unique_words(text_array) {
var hash_table, i, unique_words, keys;
hash_table = {};
for(i = 0; i < text_array.length; i++) {
if(hash_table[text_array[i]] === undefined) {
hash_table[text_array[i]] = 1;
} else {
hash_table[text_array[i]]++;
}
}
// go through the hash table and get all the unique words
unique_words = [];
keys = Object.keys(hash_table);
for(i = 0; i < keys.length; i++) {
if(hash_table[keys[i]] === 1) {
unique_words.push(keys[i]);
}
}
return unique_words.sort();
}
console.log(get_unique_words(
['blah', 'blah', 'blah', 'goose', 'duck',
'mountain', 'rock', 'paper', 'rock', 'scissors']
));
Some issues and suggestions :
Don't use var twice for the same variable.
Browsers deal with it ok, but for clarity you should only be declaring your variables once.
Always localize your loop counters - forgetting a var before your i and j will cause them to become global variables.
This is relevant when you have a page with lots of code - all global variables will show up in the debugger's watch list at all times, making it harder to debug your code.)
Use the array literal notation [] instead of the function form Array.
The function form is longer and it's easier to forget the new. It's also easier to read (IMO).
Use more whitespace (it won't bite), such as before and after an equals sign:
var x = 1;
// vs.
var x=1;
It makes the code easier to read and most people don't overdo it.
Indent your code when it's inside a block (e.g. function, if, else, while, for, etc.).
This makes it easier to read the control flow of the code and will help prevent bugs.
Use three equals signs (===) unless you are using loose equality on purpose.
This will help someone looking at your code later (probably yourself) understand better what the test is supposed to be testing.
I have a JSON response like this:
var errorLog = "[[\"comp\",\"Please add company name!\"],
[\"zip\",\"Please add zip code!\"],
...
Which I'm deserializing like this:
var log = jQuery.parseJSON(errorLog);
Now I can access elements like this:
log[1][1] > "Please add company name"
Question:
If I have the first value comp, is there a way to directly get the 2nd value by doing:
log[comp][1]
without looping through the whole array.
Thanks for help!
No. Unless the 'value' of the first array (maybe I should say, the first dimension, or the first row), is also it's key. That is, unless it is something like this:
log = {
'comp': 'Please add a company name'
.
.
.
}
Now, log['comp'] or log.comp is legal.
There are two was to do this, but neither avoids a loop. The first is to loop through the array each time you access the items:
var val = '';
for (var i = 0; i < errorLog.length; i++) {
if (errorLog[i][0] === "comp") {
val = errorLog[i][1];
break;
}
}
The other would be to work your array into an object and access it with object notation.
var errors = {};
for (var i = 0; i < errorLog.length; i++) {
errors[errorLog[i][0]] = errorLog[i][1];
}
You could then access the relevant value with errors.comp.
If you're only looking once, the first option is probably better. If you may look more than once, it's probably best to use the second system since (a) you only need to do the loop once, which is more efficient, (b) you don't repeat yourself with the looping code, (c) it's immediately obvious what you're trying to do.
No matter what you are going to loop through the array somehow even it is obscured for you a bit by tools like jQuery.
You could create an object from the array as has been suggested like this:
var objLookup = function(arr, search) {
var o = {}, i, l, first, second;
for (i=0, l=arr.length; i<l; i++) {
first = arr[i][0]; // These variables are for convenience and readability.
second = arr[i][1]; // The function could be rewritten without them.
o[first] = second;
}
return o[search];
}
But the faster solution would be to just loop through the array and return the value as soon as it is found:
var indexLookup = function(arr, search){
var index = -1, i, l;
for (i = 0, l = arr.length; i<l; i++) {
if (arr[i][0] === search) return arr[i][1];
}
return undefined;
}
You could then just use these functions like this in your code so that you don't have to have the looping in the middle of all your code:
var log = [
["comp","Please add company name!"],
["zip","Please add zip code!"]
];
objLookup(log, "zip"); // Please add zip code!
indexLookup(log, "comp"); // Please add company name!
Here is a jsfiddle that shows these in use.
Have you looked at jQuery's grep or inArray method?
See this discussion
Are there any jquery features to query multi-dimensional arrays in a similar fashion to the DOM?