Checking an input against a specific array string - javascript

I am trying to create a quiz that randomly selects a question from pool of questions in an array, which is answered in an input box that is to be checked against the corresponding answer string in the array. I used math.floor(math.random() *); to get my random number. The random number is intended to be used to find both the question and answer, which are arranged in order to correspond to one another, e.g. ['question1','question2'] and ['answer1','answer2'].
I am having difficulty with trying to get my input to properly be checked against the corresponding answer value from the array. I am fairly novice at Javascript, so I am not sure as to how to do this. I tried using the document.getElementById command to compare the two. I suspect it has something to do with the fact that ansNum doesn't get the value of questNum because of the fact that questNum is only given its value inside the generateQuiz function. (I realize ansNum is likely redundant, but I was just playing around to see if anything would happen)
Javascript:
const questions = ['What do young Roman males wear?','Who is the Roman god of the smith?','Who is the 6th king of Rome?'];
const answers = ['toga praetexta','vulcan','servius tullius'];
function getQuestNum() {
questNum = Math.floor(Math.random() * 3);
};
function getAnsNum() {
ansNum = questNum();
}
function generateQuiz() {
getQuestNum();
document.getElementById("question").innerHTML = questions[questNum];
};
function checkCorrect() {
getAnsNum();
if (answer[ansNum] = document.getElementById("input").innerHTML) {
document.getElementById("verification").innerHTML = "Correct!";
}
};
Codepen Link
An image of the code

Based on your code, I fixed it with some changes. It is not the best way to do this i think. I posted the js part here.
const questions = ['What do young Roman males wear?','Who is the Roman god of the smith?','Who is the 6th king of Rome?'];
const answers = ['toga praetexta','vulcan','servius tullius'];
var questNum;
function getQuestNum() {
questNum = Math.floor(Math.random() * 3);
};
function getAnsNum() {
ansNum = questNum;
}
function generateQuiz() {
getQuestNum();
document.getElementById("question").innerHTML = questions[questNum];
};
function checkCorrect() {
getAnsNum();
if (answers[ansNum] = document.getElementById("input").value) {
document.getElementById("verification").innerHTML = "Correct!";
}
};
First you need a global variable questNum then you can use it in all of your functions.
The function getAnsNum() is redundant, at least i think so, just use questNum in your checkCorrect() function.
For getElementByID function, insert an ID attribute to your input
<input id="input" type="text" name="input">
For input, if you want to take the value of the input field, use document.getElementById("input").value instead of innerHTML.
If you not sure about any result, console.log it or use Chrome dev debug tool to check the result. In the checkCorrect function, your array name should be answers instead of answer.
Shorter ver:
const questions = ['What do young Roman males wear?','Who is the Roman god of the smith?','Who is the 6th king of Rome?'];
const answers = ['toga praetexta','vulcan','servius tullius'];
var questNum;
function getQuestNum() {
questNum = Math.floor(Math.random() * 3);
};
function generateQuiz() {
getQuestNum();
document.getElementById("question").innerHTML = questions[questNum];
};
function checkCorrect() {
if (answers[questNum] = document.getElementById("input").value) {
document.getElementById("verification").innerHTML = "Correct!";
}
};

It would be simpler to create an array of objects that each contain both a question and an answer - and create a function that generates your random number and returns the object at the corresponding index.
Then you'll have access to everything you need without worrying about whether or not you can maintain access to the original randomly selected number, or matching up indices between two different arrays.

Related

Selecting a value and assigning as a variable is not working

For a Hangman game, I have some topics (eg:cities and animals).
When the user selects one of the topics, the outcome should be one of the chosen topic's random item. eg: London or Zebra etc.
Currently I only have random letter of selected topic.
const cities = ["New York", "London", "Berlin"]
const animals = ["Alligator", "Alpaca", "Zebra"]
const topicsEl = document.querySelector("#topics")
function randomTopic(){
return topicsEl.value[Math.floor(Math.random()*topicsEl.value.length)]
}
topicsEl.addEventListener("change", function(){
console.log(randomTopic());
})
<div class="select">
<label for="topics">Choose a topic:</label>
<select id="topics">
<option value=cities>Cities</option>
<option value=animals>Animals</option>
</select>
</div>
You seem to have issues getting a random value of a list depending on a selection.
Currently, you are selecting a random letter of topicsEl.value instead of a random element of the associated topic's list.
You need to determine the list to choose from depending on topicsEl.value. Dynamically this can be achieved if that value can be used as a key (e.g. for a dictionary), but this can also be done statically.
But doing it statically would result in duplicate code, e.g. in an if-else-if ladder growing for each new topics list:
function randomTopic() {
if (topicsEl.value === "cities") {
// ... (use citites)
} else if (topicsEl.value === "animals") {
// ... (use animals)
} // Etc. for every new topic
}
Doing it dynamically allows for abstracting away the list selection, keeping the function simple. As suggested before, a dictionary can be used for this.
For example, your dictionary's properties could each be a topic list, and your option values should then match their corresponding property's name:
const topics = {
cities: [/*...*/],
animals: [/*...*/]
};
const topicsEl = document.querySelector("#topics");
function randomTopic() {
const list = topics[topicsEl.value];
// ...
}
Selecting a random item of that list works analogous to how you are currently selecting a random letter:
function randomTopic() {
const list = topics[topicsEl.value];
return list[Math.floor(Math.random() * list.length)];
}
Personally, I find such random selections more readable if the index generation is in a separate function. Example:
const edibles = ["cheese", "ham", "bread", "banana", "peanuts"];
console.log(randomEdible());
function randomEdible() {
return edibles[randomInt(0, edibles.length - 1)];
}
function randomInt(max = 100, min = 0) {
if (max < min) {
[max, min] = [min, max]; // Swap
}
return Math.floor(Math.random() * (max - min + 1) + min); // +1 to include max
}
In your existing code, topicsEl.value is going to be the string "cities" or the string "animals" (because those are the value of each of the options in your <select> box.). These are not the global variables you defined in your javascript, they're just strings contained in the HTML.
You then, in randomTopic(), access that string as an array, which Javascript interprets as you wanting two treat it as an array of the characters within that string. This is why you're getting a random letter from the word: "animals"[0] is the letter a, "animals"[1] is the letter n, and so on.
What you're trying to do is choose a random item from the array variables you've named "cities" and "animals", but your functions don't try to touch those variables, they're only acting on the strings contained in the DOM.
So you need to add a step, to get from the string value from the <select> to the array you're trying to access.
You've defined the two arrays as global variables; in theory those can be accessed as window.cities or window.animals, so you could do window[topicsEl.value] which would return the array you're trying to access.... it's not great practice to depend on the window global, though, so I'd encourage you to switch that pair of separate variables in to an object for easier access:
const topics = {
cities: ["New York", "London", "Berlin"],
animals: ["Alligator", "Alpaca", "Zebra"]
}
const topicsEl = document.querySelector("#topics")
function randomTopic() {
// find the desired array:
let topicArr = topics[topicsEl.value]
// return a random element from that array:
return topicArr[Math.floor(Math.random() * topicArr.length)]
}
topicsEl.addEventListener("change", function() {
console.log(randomTopic());
})
<div class="select">
<label for="topics">Choose a topic:</label>
<select id="topics">
<option value=cities>Cities</option>
<option value=animals>Animals</option>
</select>
</div>

I want to generate unique ID

I want to generate unique ID in JavaScript. I have tried uuid npm package, it's good but it's not what I want.
For example what I get as a result from generating unique ID from uuid package is
9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d
Is there any way to make specific format as I want.
For example I want my ID to look like this
XZ5678
In this example format is two uppercase letters and 4 numbers.
That's it, I'm looking for answer and thank you all in advance.
If you're just looking to generate a random sequence according to that pattern, you can do so relatively easily. To ensure it's unique, you'll want to run this function and then match it against a table of previously generated IDs to ensure it has not already been used.
In my example below, I created two functions, getRandomLetters() and getRandomDigits() which return a string of numbers and letters the length of the argument passed to the function (default is length of 1 for each).
Then, I created a function called generateUniqueID() which generates a new ID according to the format you specified. It checks to see if the ID already exists within a table of exiting IDs. If so, it enters a while loop which loops until a new unique ID is created and then returns its value.
const existingIDs = ['AA1111','XY1234'];
const getRandomLetters = (length = 1) => Array(length).fill().map(e => String.fromCharCode(Math.floor(Math.random() * 26) + 65)).join('');
const getRandomDigits = (length = 1) => Array(length).fill().map(e => Math.floor(Math.random() * 10)).join('');
const generateUniqueID = () => {
let id = getRandomLetters(2) + getRandomDigits(4);
while (existingIDs.includes(id)) id = getRandomLetters(2) + getRandomDigits(4);
return id;
};
const newID = generateUniqueID();
console.log(newID);
Not sure why you want this pattern but you could do like this:
const { floor, random } = Math;
function generateUpperCaseLetter() {
return randomCharacterFromArray('ABCDEFGHIJKLMNOPQRSTUVWXYZ');
}
function generateNumber() {
return randomCharacterFromArray('1234567890');
}
function randomCharacterFromArray(array) {
return array[floor(random() * array.length)];
}
const identifiers = [];
function generateIdentifier() {
const identifier = [
...Array.from({ length: 2 }, generateUpperCaseLetter),
...Array.from({ length: 4 }, generateNumber)
].join('');
// This will get slower as the identifiers array grows, and will eventually lead to an infinite loop
return identifiers.includes(identifier) ? generateIdentifier() : identifiers.push(identifier), identifier;
}
const identifier = generateIdentifier();
console.log(identifier);
They way of what you are suggesting be pretty sure you are going to get duplicates and collitions, I strongly suggest go with uuid.
Also probably you can find this useful: https://www.npmjs.com/package/short-uuid
Or if you want to continue with your idea this could be helpful: Generate random string/characters in JavaScript

Function that takes an input text, checks if it has certain elements, and returns an output value (JS)

I'm kind of new to JavaScript, and I hope someone can help me figure out how to develop an application that:
Takes a text value from an HTML input when pressing a button;
Check if that text value has certain syllables (e.g. if it has the syllables "ba", "ca", and "da" in it);
returns a value to the HTML output whether or not it has syllables.
Obs. HTML is no problem. My focus is on JS.
I know it sounds simple, but I would like at least a direction from where to start. I already realized that I will have to have at least two variables, one for the text value
const text = document.getElementById("name").value;
and another one for the syllables that I intend to check
constant syllable = ["ba", "ca", "da", "fa", "ra"];
Am I in the right direction? My problem starts when I try to write the functions. Anyway, I appreciate any help. Thanks.
you can use find on array and includes in a string
const syllable = ["ba", "ca", "da", "fa", "ra"];
validate = (word) => {
if (!word) {
return false;
}
let res = syllable.find(i => word.includes(i));
return res ? true : false
}
console.log(validate("aadaa"))
Your questions is a little vague, but I hope this answers it. I've included some explanation about how it all works.
// You define a function using 'function <identifier>(){<functionbody>}' (generally)
function containsSyllables(text_value, syllables) {
// parameters are set here ^^^^^^^^^^^^^
let foundSyllable = false; // <-- keep track of whether or not we've found a matching syllable
// this loops through each item in `syllables` (we refer to each item as `syllable`)
for (let syllable of syllables) {
// You can use the String.prototype.includes(substring) method to check if a string contains a substring
if (text_value.includes(syllable)) {
foundSyllable // <-- keep track that we've found a syllable in the text_value
break // exit this loop if we found a matching syllable
}
}
return foundSyllable
// return the variable that kept track of whether or not we found a syllable
}
var result = containsSyllables("bad", ["ca", "ba"]);
console.log(`"bad" contains "ca" or "ba"? ${result}`);
// OUTPUTS: "bad" contains "ca" or "ba"? false
There are some improvements you could make to this function, but I think this gets the point across simply.
If there is a line in this that you do not understand, you can search up roughly what it is: e.g. "for loop javascript". Look for a MDN link, they're the best.
You can take your element with getElementById, like you did, add event on it with a function name.addEventListener('input', updateValue); then check if your input includes one of your substrings from array and print a message as result ( check array.some)
const syllable = ["ba", "ca", "da", "fa", "ra"];
const name = document.getElementById("nameInput");
name.addEventListener('input', checkForSyllables);
function checkForSyllables(e) {
const value = e.target.value;
if (syllable.some(syllable => value.includes(syllable))) {
console.log(value) // your word contains one of elements from array
document.getElementById("result").innerHTML = value + " contains syllable";
}
}
<p> Name: </p>
<input type="text" id="nameInput" keyup="onKeyUp">
<p id="result" />

Comparing 2 Json Object using javascript or underscore

PS: I have already searched the forums and have seen the relevant posts for this wherein the same post exists but I am not able to resolve my issue with those solutions.
I have 2 json objects
var json1 = [{uid:"111", addrs:"abc", tab:"tab1"},{uid:"222", addrs:"def", tab:"tab2"}];
var json2 = [{id:"tab1"},{id:"new"}];
I want to compare both these and check if the id element in json2 is present in json1 by comparing to its tab key. If not then set some boolean to false. ie by comparing id:"tab1" in json2 to tab:"tab1 in json1 .
I tried using below solutions as suggested by various posts:
var o1 = json1;
var o2 = json2;
var set= false;
for (var p in o1) {
if (o1.hasOwnProperty(p)) {
if (o1[p].tab!== o2[p].id) {
set= true;
}
}
}
for (var p in o2) {
if (o2.hasOwnProperty(p)) {
if (o1[p].tab!== o2[p].id) {
set= true;
}
}
}
Also tried with underscore as:
_.each(json1, function(one) {
_.each(json2, function(two) {
if (one.tab!== two.id) {
set= true;
}
});
});
Both of them fail for some test case or other.
Can anyone tell any other better method or outline the issues above.
Don't call them JSON because they are JavaScript arrays. Read What is JSON.
To solve the problem, you may loop over second array and then in the iteration check if none of the objects in the first array matched the criteria. If so, set the result to true.
const obj1 = [{uid:"111", addrs:"abc", tab:"tab1"},{uid:"222",addrs:"def", tab:"tab2"}];
const obj2 = [{id:"tab1"},{id:"new"}];
let result = false;
for (let {id} of obj2) {
if (!obj1.some(i => i.tab === id)) {
result = true;
break;
}
}
console.log(result);
Unfortunately, searching the forums and reading the relevant posts is not going to replace THINKING. Step away from your computer, and write down, on a piece of paper, exactly what the problem is and how you plan to solve it. For example:
Calculate for each object in an array whether some object in another array has a tab property whose value is the same as the first object's id property.
There are many ways to do this. The first way involves using array functions like map (corresponding to the "calculate for each" in the question, and some (corresponding to the "some" in the question). To make it easier, and try to avoid confusing ourselves, we'll do it step by step.
function calculateMatch(obj2) {
return obj2.map(doesSomeElementInObj1Match);
}
That's it. Your program is finished. You don't even need to test it, because it's obviously right.
But wait. How are you supposed to know about these array functions like map and some? By reading the documentation. No one help you with that. You have to do it yourself. You have to do it in advance as part of your learning process. You can't do it at the moment you need it, because you won't know what you don't know!
If it's easier for you to understand, and you're just getting started with functions, you may want to write this as
obj2.map(obj1Element => doesSomeElementInObj1Match(obj1Element))
or, if you're still not up to speed on arrow functions, then
obj2.map(function(obj1Element) { return doesSomeElementInObj1Match(obj1Element); })
The only thing left to do is to write doesSomeElementInObj2Match. For testing purposes, we can make one that always returns true:
function doesSomeElementInObj2Match() { return true; }
But eventually we will have to write it. Remember the part of our English description of the problem that's relevant here:
some object in another array has a tab property whose value is the same as the first object's id property.
When working with JS arrays, for "some" we have the some function. So, following the same top-down approach, we are going to write (assuming we know what the ID is):
In the same way as above, we can write this as
function doesSomeElementInObj2Match(id) {
obj2.some(obj2Element => tabFieldMatches(obj2Element, id))
}
or
obj2.some(function(obj2Element) { return tabFieldMatches(obj2Element, id); })
Here, tabFieldMatches is nothing more than checking to make sure obj2Element.tab and id are identical.
We're almost done! but we still have to write hasMatchingTabField. That's quite easy, it turns out:
function hasMatchingTabField(e2, id) { return e2.tab === id; }
In the following, to save space, we will write e1 for obj1Element and e2 for obj2Element, and stick with the arrow functions. This completes our first solution. We have
const tabFieldMatches = (tab, id) { return tab === id; }
const hasMatchingTabField = (obj, id) => obj.some(e => tabFieldMatches(e.tab, id);
const findMatches = obj => obj.some(e => hasMatchingTabField(e1, obj.id));
And we call this using findMatches(obj1).
Old-fashioned array
But perhaps all these maps and somes are a little too much for you at this point. What ever happened to good old-fashioned for-loops? Yes, we can write things this way, and some people might prefer that alternative.
top: for (e1 of obj1) {
for (e2 of (obj2) {
if (e1.id === e2.tab) {
console.log("found match");
break top;
}
}
console.log("didn't find match);
}
But some people are sure to complain about the non-standard use of break here. Or, we might want to end up with an array of boolean parallel to the input array. In that case, we have to be careful about remembering what matched, at what level.
const matched = [];
for (e1 of obj1) {
let match = false;
for (e2 of obj2) {
if (e1.id === e2.tab) match = true;
}
matched.push(match);
}
We can clean this up and optimize it bit, but that's the basic idea. Notice that we have to reset match each time through the loop over the first object.

Create Dictionary in Javascript / PHP

I'm trying to create a dictionary from a .txt file in the shape of a tree. On every line of the text file there's a word, I extract all those words in an array.
Now regarding the tree, Each node contains a letter, if it's the last letter of a word, it contains a definition, and each node have an array Children that contains letters from all others words starting the same way.
So I have nodes defined this way:
function Node(letter,definition,children) {
this.letter = letter,
this.definition = "",
this.children = []
};
I have an array Dictionary that will contain all the nodes. Every Node will be organized (so that we know 'a' is in Dictionary[0] and 'b' in Dictionary[1] and so on).
I defined some functions to help build the dictionary:
check if Dictionary contains the first letter of the word we have (c is the character, dictio is the dictionary array and ascii is the ascii-97 value of the character)
function checkChar(c,dictio,ascii){
if(dictio[ascii].letter == c ){
return true;
}
return false;
};
create a node with the given character
function createChar(c){
var noeud = {
letter: c,
def: '',
children: []
};
return noeud;
};
Add the character to the dictionary
function addChar(c,dictio,ascii){
dictio.children[ascii] = createChar(c);
};
And I'm having trouble on the biggest function: the main on that adds the word and calls all of these small functions I've written. Which I'm having trouble making.
I don't even know if what I'm doing is right or wrong, if anyone could point me to the right direction or suggest a method in javascript or php to do dictionary from a TXT file that would be great.
Ok...
so this is an example of txt file containing words
//words.txt
hello
world
foo
bar
word_dictionary.php for parsing txt file and has method for checking if a word exists in tree/dictionary
<?php
//word_dictionary.php
class Node{
private $letter;
private $definition = '';
private $children = array();
function __construct($letter){
$this->letter = $letter;
}
function hasChild($letter){
return array_key_exists($letter,$this->children);
}
function addChild($letter){
$this->children[$letter] = new Node($letter);
return $this->children[$letter];
}
function getChild($letter){
return $this->children[$letter];
}
function setDefinition($definition){
$this->definition = $definition;
}
function getDefinition(){
return $this->definition;
}
function hasDefinition(){
return (bool)$this->definition;
}
}
// method for getting a word definition from tree/dictionary.
// if word exists return definition, else return false
function getDefinition($word,$tree){
$node = $tree;
$length = strlen($word);
foreach(str_split($word) as $index => $letter){
if($node->hasChild($letter)){
$node = $node->getChild($letter);
}
else{ // word not exists
return false;
}
if(($index+1) == $length){ // means last letter in word
return ($node->hasDefinition()) ? $node->getDefinition() : false;
}
}
}
// Start build your tree/dictionary. This part is execute ONCE only for building tree.
$anchor = new Node('');
$handle = fopen('words.txt','r');
while(($word = fgets($handle))){
$word = rtrim($word);
$length = strlen($word);
$node = $anchor;
foreach(str_split($word) as $index => $letter){
if($node->hasChild($letter)){
$node = $node->getChild($letter);
}
else{
$node = $node->addChild($letter);
}
if(($index+1) == $length ){
//print 'definition for word: '.$word."\n";
$node->setDefinition('definition for world: '.$word);
}
}
}
//use this function when a user type a word that you want to check if exists and return the definition to user. this flow should be in AJAX request from client
print getDefinition('bar',$anchor)."\n";
hope it help a bit ;)
first of all, you're asking if you are going in the right direction. Well, i think you are. This may not be the best implementation of the year but still all the things you said are coherent with each other and it seems pretty solid.
I don't think giving you a direct solution to your question would be didactic since you're working with trees and it seems you don't have much experience with them.
But i can give you some hint and references. A very convenient way to implement your "biggest function :)" would be to use a recursive function which would call itself on each children.
I suggest you take a look a this wikipedia article. It shows example of trees that look a bit like yours and implement a full search algorithm that you could adapt to your needs without too much problem.
Hope the english wasn't that bad, and that it will help you

Categories

Resources