I haven't found this answer anywhere, and have been on the lookout for a few months, so my apologies if I'm overlooking something that should be obvious. Self-taught and came upon a rather vexing gap in my knowledge here.
In an rather complex yarn of connected pieces, I have two globally-scoped (basically static) variables and an array of character types outside of the main onclick function, as such:
var missingWut = ["child","spouse","talisman","relic","sock"];
var rdmmissingWut;
var pronounA = "he";
var charTypes = [
["goatherd",pronounA+" wants to find a missing goat","kind"],
["shepherd",pronounA+" wants to find a missing sheep","cruel"],
["detective",pronounA+" wants to find a missing "+missingWut[rdmmissingWut],"spidery"],
...,
..., //this goes on for awhile; the array is currently 500 items long and has way more subindexes than I wanted/needed to include in this example.
];
We've declared the variable names in the line above, but obviously rdmmissingWut is undefined at this point.
We then - for the sake of memory - go on to define rdmmissingWut inside the function, thereby updating its value from undefined to a random index number:
rdmmissingWut = Math.floor(Math.random()*missingWut.length);
rdmcharType = Math.floor(Math.random()*charTypes.length);
before assigning a random charType index to character 1 (char1).
var char1 = charTypes[rdmcharType];
My question is this -
Is there a way to update the variable value within the array - after I've updated the variable - without redefining the entire array?
One could obviously just reiterate the definition of the array, at which point it would update all variable values with their current value, but that seems really clumsy, cluttered and inefficient.
Another use case (with the same issue):
I want to use this same chartypes array to randomly roll a character type for character 2 (char2) - and eventually, char3 & char4, as well. But let's say char2 (or 3 or 4) is female. To do this, after char1 was defined, I would then need to update the value of pronounA to "she" and thereupon update the pronounA definition in every instance within the charTypes array before selecting a random charTypes index for her - correct? What is the best way to accomplish this? I'm sure there must be some elegant solution that I'm just ignorant of.
Thanks for your help.
You'll be needing to evaluate that variable every time you run through your array, so I'd recommend a placeholder that can be replaced with .replaceAll
var missingWut = ["child", "spouse", "talisman", "relic", "sock"];
var rdmmissingWut;
var pronounA = "he";
var charTypes = [
["goatherd", pronounA + " wants to find a missing goat", "kind"],
["shepherd", pronounA + " wants to find a missing sheep", "cruel"],
["detective", pronounA + " wants to find a missing _missingWut_", "spidery"]
];
function getMissingWut() {
return missingWut[rdmmissingWut || 0]; // this uses zero incase the value hasn't been updated
}
console.log(charTypes.flat().join("\n").replaceAll(/_missingWut_/g, getMissingWut()))
rdmmissingWut = 4
console.log(charTypes.flat().join("\n").replaceAll(/_missingWut_/g, getMissingWut()))
Related
The case is:
function trocaPrimeiroEUltimo(array) {
array.array[0]
array.array[array.length - 1]
return array
}
I did this way, but it didn't work. I can't change the structure of the function, just what it's inside. Someone, could please help me?
Do you want to replace the last value with the first value?
if so, do:
temp = array[0]
array[0] = array[array.length-1]
array[array.length-1] = temp
That's a simple swap.
The syntax makes use of new ES6 capabilities (destructuring an array). This way the exchange can be done without a temporary variable.
The whole thing can even be done as a one-liner:
const arr=[7,8,9,10,11];
const swapFirstLast=(a,l)=>([a[0],a[l]]=[a[l=a.length-1],a[0]],a);
console.log(swapFirstLast(arr))
The use of the argument l is also something you probably would not do in a "real" application. I only went for it so I would not have to define the variable locally. l is assigned a value on the right hand side of the assignment expression. By the time the result needs to be stored l has been calculated and can also be used for addressing the right target element.
I'm creating a quiz app using Javascript and I've come across an error that is puzzling me so I decided to post it on here and maybe someone sees something different then me.
I have an object of arrays called quizQ --- inside this object is my question and answer list. It is structured like this - I should mention that testbank does get initialized into quizQ in another function in my script file and all the console.logs confirm this, so the problem must lie in the for loop
var testBank = [
{
qTitle: "Commonly used data types DO NOT include:",
picks: ["strings", "booleans", "alerts", "numbers"],
ans: "alerts"
},
{
qTitle: "The condition in an if / else statement is enclosed within ____.",
picks: ["quotes", "curly brackets", "parentheses", "square brackets"],
ans: "parentheses"
},
{
qTitle: "Is JavaScript fun to work with?",
picks: ["No", "Sometimes", "What is Javascript", "Not just yes, but HELL YES!"],
ans: "Not just yes, but HELL YES!"
},
{
qTitle: "DOM is an abreviation for ____",
picks: ["Data Object Mode", "Dumb Old Man", "Document Object Model", "Dutle Opo Mipsy"],
ans: "Document Object Model"
},
--- Pretty simple questions I pulled from another app on Github. So what I've done is created a function that will put these picks in a list so I can choose the one I want to answer with. I use the qTitle as the header for each question and after you complete it you are presented with another. ---
The problem is when I run the function and I run the for loop for it, it keeps telling me It cannot read undefined of '0' which is the first index the for runs over. Here is my code
current = quizQ.pop();
console.log(current)
let questionServed = document.createElement('h2');
questionServed.setAttribute("question", current.qTitle);
questionServed.textContent = current.qTitle;
testEl.appendChild(questionServed)
let choices = document.createElement('ul');
choices.setAttribute('id', 'choices');
testEl.appendChild(choices)
for (let i = 0; i < current.picks.length; i++) {
let pickList = document.createElement('li')
pickList.setAttribute('pick-value', current.pick[i]);
pickList.setAttribute('id', 'questionNum' + i);
pickList.textContent = current.pick[i];
choices.appendChild(pickList)
}
I've console.log(current) and it returns the last array in the testBank as expected, however when the for loop runs, it keeps giving me the error mentioned above. I assume I'm writing the statement incorrectly current.pick[i] but I assumed that it would go into current, then picks, and pull out the pick[0] which would be one of the options given.
Any help would be greatly appreciated!
A good plan to avoid this is to have a convention that arrays are named with a plural
In your case the problem is pick versus picks.
for (let i = 0; i < current.picks.length; i++) {
let pickList = document.createElement('li')
pickList.setAttribute('pick-value', current.picks[i]);
pickList.setAttribute('id', 'questionNum' + i);
pickList.textContent = current.picks[i];
choices.appendChild(pickList)
It is often difficult to remember whether the array is picks or pick. After all, when you select one element, you think to yourself that you are selecting element #3, so why shouldn't it be called pick[3]?
A convention to avoid this is that the array should be called picks, and an individual value from the array, if you need to extract it as a single item, you can call pick.
Sticking to this convention makes it easier to avoid the problem.
It's likely a typo with current.pick. Ensure all members are named correctly and consider using Typescript for future error checking.
https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html
I am making a trivia system, and the variable triviaA is changed to the updated Answer every time there is a new question. I was wondering how I could use Regex to make it so that if triviaA = 'eagle' then if someone submitted the answer as eagle but with a small spelling mistake, the if statement would still return both the triviaA answer and the players answer return true.
I'm new to Regex, please excuse my mistakes.
You can dynamically build a regular expression that matches all possible "errors" (wrong/missing/extra letter) and apply it to the source:
function fuzzyContains(word, str) {
let r = [];
for (let i = 0; i < word.length; i++) {
// wrong letter
r.push(word.slice(0, i) + '[a-z]' + word.slice(i + 1));
// missing letter
r.push(word.slice(0, i) + '' + word.slice(i + 1));
// extra letter
r.push(word.slice(0, i) + '[a-z]' + word.slice(i));
}
return new RegExp(r.join('|')).test(str)
}
console.log(fuzzyContains('eagle', 'fly, ewgle, fly'))
console.log(fuzzyContains('eagle', 'fly, eagl, fly'))
console.log(fuzzyContains('eagle', 'fly, eaggle, fly'))
console.log(fuzzyContains('eagle', 'fly, eagly, fly'))
See https://norvig.com/spell-correct.html for other interesting ideas.
This would actually be quite difficult to do with RegEx. However, there's a concept in computing called "edit distance", which is a measure of how "similar" two strings are, and there are known algorithms to calculate that. Which means there are Node packages to calculate it :)
For instance, there's the aptly named Node package edit-distance: https://www.npmjs.com/package/edit-distance (Note: edit distance is sometimes called Levenshtein edit distance, named after the man who first studied it.)
I'll give you an example using that package; other packages may work somewhat differently to calculate the same thing.
There are three types of changes between two strings: an insertion, where a character is added in one that's not in the other; a deletion, where a character is removed in one that's there in the other; and an update/substitution, where a letter is changed between the strings. Using the edit-distance package, you define a function that assigns a cost to each of these types of changes. Then you call the package's levenshtein method, passing it the two strings and the three functions, and it returns an object with a distance property that is the sum score.
Assuming your cost functions return non-negative values, a score of 0 means the two strings are identical, and higher numbers mean they're more different. So you can use this to compare the entered value with the correct string and, if the result is lower than a certain threshold, accept it as "correct excluding typos".
I have a group of strings in Javascript and I need to write a function that detects if another specific string belongs to this group or not.
What is the fastest way to achieve this? Is it alright to put the group of values into an array, and then write a function that searches through the array?
I think if I keep the values sorted and do a binary search, it should work fast enough. Or is there some other smart way of doing this, which can work faster?
Use a hash table, and do this:
// Initialise the set
mySet = {};
// Add to the set
mySet["some string value"] = true;
...
// Test if a value is in the set:
if (testValue in mySet) {
alert(testValue + " is in the set");
} else {
alert(testValue + " is not in the set");
}
You can use an object like so:
// prepare a mock-up object
setOfValues = {};
for (var i = 0; i < 100; i++)
setOfValues["example value " + i] = true;
// check for existence
if (setOfValues["example value 99"]); // true
if (setOfValues["example value 101"]); // undefined, essentially: false
This takes advantage of the fact that objects are implemented as associative arrays. How fast that is depends on your data and the JavaScript engine implementation, but you can do some performance testing easily to compare against other variants of doing it.
If a value can occur more than once in your set and the "how often" is important to you, you can also use an incrementing number in place of the boolean I used for my example.
A comment to the above mentioned hash solutions.
Actually the {} creates an object (also mentioned above) which can lead to some side-effects.
One of them is that your "hash" is already pre-populated with the default object methods.
So "toString" in setOfValues will be true (at least in Firefox).
You can prepend another character e.g. "." to your strings to work around this problem or use the Hash object provided by the "prototype" library.
Stumbled across this and realized the answers are out of date. In this day and age, you should not be implementing sets using hashtables except in corner cases. You should use sets.
For example:
> let set = new Set();
> set.add('red')
> set.has('red')
true
> set.delete('red')
true
> set.has('red')
false
Refer to this SO post for more examples and discussion: Ways to create a Set in JavaScript?
A possible way, particularly efficient if the set is immutable, but is still usable with a variable set:
var haystack = "monday tuesday wednesday thursday friday saturday sunday";
var needle = "Friday";
if (haystack.indexOf(needle.toLowerCase()) >= 0) alert("Found!");
Of course, you might need to change the separator depending on the strings you have to put there...
A more robust variant can include bounds to ensure neither "day wed" nor "day" can match positively:
var haystack = "!monday!tuesday!wednesday!thursday!friday!saturday!sunday!";
var needle = "Friday";
if (haystack.indexOf('!' + needle.toLowerCase() + '!') >= 0) alert("Found!");
Might be not needed if the input is sure (eg. out of database, etc.).
I used that in a Greasemonkey script, with the advantage of using the haystack directly out of GM's storage.
Using a hash table might be a quicker option.
Whatever option you go for its definitely worth testing out its performance against the alternatives you consider.
Depends on how much values there are.
If there are a few values (less than 10 to 50), searching through the array may be ok. A hash table might be overkill.
If you have lots of values, a hash table is the best option. It requires less work than sorting the values and doing a binary search.
I know it is an old post. But to detect if a value is in a set of values we can manipulate through array indexOf() which searches and detects the present of the value
var myString="this is my large string set";
var myStr=myString.split(' ');
console.log('myStr contains "my" = '+ (myStr.indexOf('my')>=0));
console.log('myStr contains "your" = '+ (myStr.indexOf('your')>=0));
console.log('integer example : [1, 2, 5, 3] contains 5 = '+ ([1, 2, 5, 3].indexOf(5)>=0));
You can use ES6 includes.
var string = "The quick brown fox jumps over the lazy dog.",
substring = "lazy dog";
console.log(string.includes(substring));
for (var i=a.length-1;i>0;i--) {
if (i!=a.indexOf(a.charAt(i))) {
a=a.substring(0,i)+a.substring(i+1);
}
}
I found this in a web app I'm auditing, it just baffles me why it's there.
I can't seem to see a case where i!=a.indexOf(a.charAt(i)) would be false.
The value the pass to it is:
a = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
There is no comment either //sigh
This would be true for repeated characters, since indexOf finds the first index of a string, and you're searching from the end. Example:
var a = "xyzxyz";
On first iteration, i === 4, a.charAt(4) === "x", and a.indexOf("x") === 0. So 4 !== 0.
It then sets a = a.substring(0, 4) + a.substring(5). Recalling at substring is inclusive in the first index but exclusive in the last index, that means in this case a = "xyz" + "yz", so we have removed the duplicate "x" from the string.
Since the loop traverses backward, this will continue to work even for characters repeated more than once; you can see that the portion a.substring(i + 1) will always have been covered by the algorithm already, i.e. not contain any duplicates.
As always when encountering this type of thing, applying the extract method refactoring would be a great way to make the code clearer. (Even better than commenting it!) So if you just pulled this out into a method, the code could become a = removeDuplicateChars(a), and everyone is much happier.