Weird JavaScript Code - javascript

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.

Related

JavaScript string.includes() method at specific index, without modifying original string?

I am wondering if there's a way to use the str.includes() function in JavaScript, but check at a certain index of the string, without changing the original string. For example:
var str = "this is a test";
str.includes("test"); //returns true
str.includes("test", 0) //returns false, as "test" is not at position 0
str.includes("test", 10) //returns true, as "test" is at position 10 in the string
I've been trying to find a way to do this, but haven't been able to figure it out. Could somebody please help me?
String.prototype.includes() has something close to this functionality, as argument 2 is taken as the start position for searching.
If you want to search at, not after, a specific index, you can write a function that takes the string, creates a slice of it, and checks if that slice matches
function substring_at(string, substring, position) {
let slice = string.slice(position, position + substring.length)
// Triple equals removes type coercion support, and is slightly faster
return slice === substring
}
I've tested it with your examples and all seems well.

Finding a valid substring

I am a bit puzzled by one exercise I recently came across with.
It seems like an easy task and I've put my solution but it turned out it didn't pass all the tests :D
In the example, I've found two example substrings:
Input: S = "(()("
Output: 2
Explanation: The longest valid
substring is "()". Length = 2.
and
Input: S = "()(())("
Output: 6
Explanation: The longest valid
substring is "()(())". Length = 6.
at the first glance, everything is clear.
I came up with my solution:
class Solution {
findMaxLen(s) {
if (!s || !s.length) throw new Error('Invalid input value provided')
let openIndex = null
let closingIndex = null
for (let i = 0; i < s.length; i++) {
if (s[i] == '(' && !openIndex) openIndex = i + 1
if (s[i] == ')') closingIndex = i + 1
}
if(!closingIndex || !openIndex) throw new Error('Invalid substring')
return closingIndex - openIndex + 1
}
}
So, my solution should solve the issue of trying to find The longest substring with the opening and closing parentheses.
But it failed the test with an input value: (((()
Where the correct answer is 2 and my output is 5
Is this (((() different from ()(())( one provided in the example?
I suppose I do not wholly understand the idea of what the substring is or something...
This pseudocode should work. Some bugs or edge cases might have loose ends as I just wrote this here on the fly. Feel free to test it and point out the misses.
helper_stack = null
max_valid_len = 0
running_len = 0
for i=0 to input_s.length:
if helper_stack.length == 0:
if input_s[i] == ')':
running_len = 0
continue
else:
helper_stack.push('(')
else:
if input_s[i] == '(':
helper_stack.push('(')
else:
helper_stack.pop()
running_len += 2
if running_len > max_valid_len:
max_valid_len = running_len
EDIT: Explanation
With your logic, you are not keeping track of order of opening and closing of brackets, which is important. If a closing bracket precedes open, string becomes invaid by default. Hence, using stack makes sense here.
If ever we encounter a closing bracket before open, we restart from that point. Hence, we set the running_len = 0. For every encounter of closing bracket, if an open bracket is there to balance it, we just pop it off, and since its a pair (of chars, when we consider length of string), running_len += 2 is done.
With little modification, we can even reproduce max_valid_substring if needed. However, in our case, we could even use just an integer instead of helper_stack. For every push('(') operation, just do var += 1, and var -= 1 for pop and that should also do the trick. Note that here, we are not explicitly using stack, but this is still conceptually LIFO = last in first out which is basically, stack.

Why is my script saying '(' === ')' is true?

I was doing this kata on codewars. The question wants the function to return true if the first argument (string) passed in ends with the 2nd argument (also a string). So I wrote my function and everything worked just fine until it compares ':-)' with ':-(' and returns true.
What is wrong? I'm so confident that my code should work that I don't even know what to search for.
function solution(str, ending){
if (!ending) return true; // if ending is a empty string return true (the question wants that)
let ok;
const strArr = str.split(''), endingArr = ending.split('');
for (let i = 0; i < endingArr.length; i++) strArr.reverse()[i] === endingArr.reverse()[i] ? ok = true : ok = false;
return ok;
}
console.log(solution(":-)",":-("));
Your problem is a misunderstanding of what reverse() does. It does not return a reversed copy of the old array, it reverses the existing array and returns that same array. As a result, you keep reversing the arrays back and forth every iteration of the loop, causing some elements to be skipped and some to be checked twice.
Array.prototype.reverse() on MDN
Edit:
As pointed out by others in the comments, both to the question and this answer, there are in fact multiple problems.
reverse() aside, the loop always sets ok to the result of the last comparison, making the function ignore all previous results.
The easier way to implement this is to remove ok altogether. Instead, return false as soon as a mismatch is detected. If the function runs long enough to exit the loop, it means no mismatch was detected and true can be returned.
Edit 2:
Just as a friendly suggestion:
While both reverse() and ok are real issues with the code, I only noticed the first one the first time around due to the formatting of the code. The ok problem was off-screen due to the line being too long. As such, once I spotted the reverse() issue, I assumed that was it and didn't bother scrolling sideways to see the rest of the code.
I am not going to demand that you write your own code in a certain way, but if you format it properly, it allows others to read it more easily. In essence, you help us to more easily help you.
For instance, this line:
for (let i = 0; i < endingArr.length; i++) strArr.reverse()[i] === endingArr.reverse()[i] ? ok = true : ok = false;
...would have been significantly easier to read as...
for (let i = 0; i < endingArr.length; i++) {
if(strArr.reverse()[i] === endingArr.reverse()[i])
ok = true;
else
ok = false;
}
...or some variation thereof. Here, the problem is significantly more visible and obvious.
The other answer explains many of the mistakes you've made. I wanted to point out just how much you've over-thought your solution.
function solution(str, ending){
if (ending === "") return true; // if ending is a empty string return true (the question wants that)
return str.endsWith(ending);
}
console.log(solution(":-)",":-("));
console.log(solution("foo",""));
console.log(solution("foo","bar"));
console.log(solution("foobar","bar"));
Even my solution above is overengineered, str.endsWith("") always returns true. So this can be simplified further.
function solution(str, ending){
return str.endsWith(ending);
}
console.log(solution(":-)",":-("));
console.log(solution("foo",""));
console.log(solution("foo","bar"));
console.log(solution("foobar","bar"));

How to use Regex to see if String matches another string partially (or completely)?

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".

How to access the first two digits of a number

I want to access the first two digits of a number, and i have tried using substring, substr and slice but none of them work. It's throwing an error saying substring is not defined.
render() {
let trial123 = this.props.buildInfo["abc.version"];
var str = trial123.toString();
var strFirstThree = str.substring(0,3);
console.log(strFirstThree);
}
I have tried the above code
output of(above code)
trial123=19.0.0.1
I need only 19.0
How can i achieve this?
I would split it by dot and then take the first two elements:
const trial = "19.0.0.1"
console.log(trial.split(".").slice(0, 2).join("."))
// 19.0
You could just split and then join:
const [ first, second ] = trial123.split('.');
const result = [ first, second ].join('.');
I have added a code snippet of the work: (explanation comes after it, line by line).
function getFakePropValue(){
return Math.round(Math.random()) == 0 ? "19.0.0.1" : null;
}
let trial123 = getFakePropValue() || "";
//var str = trial123.toString();
// is the toString() really necessary? aren't you passing it along as a String already?
var strFirstThree = trial123.split('.');
//var strFirstThree = str.substring(0,3);
//I wouldn't use substring , what if the address 191.0.0.1 ?
if(strFirstThree.length >= 2)
console.log(strFirstThree.splice(0,2).join("."));
else
console.error("prop was empty");
Because you are using React, the props value was faked with the function getFakePropValue. The code inside is irrelevant, what I am doing is returning a String randomly, in case you have allowed in your React Component for the prop to be empty. This is to show how you an create minimal robust code to avoid having exceptions.
Moving on, the following is a safety net to make sure the variable trial123 always has a string value, even if it's "".
let trial123 = getFakePropValue() || "";
That means that if the function returns something like null , the boolean expression will execute the second apart, and return an empty string "" and that will be the value for trial123.
Moving on, the line where you convert to toString I have removed, I assume you are already getting the value in string format. Next.
var strFirstThree = trial123.split('.');
That creates an array where each position holds a part of the IP addrss. So 19.0.0.1 would become [19,0,0,1] that's thanks to the split by the delimiter . . Next.
if(strFirstThree.length >= 2)
console.log(strFirstThree.splice(0,2).join("."));
else
console.error("prop was empty");
This last piece of code uses the conditional if to make sure that my array has values before I try to splice it and join. The conditional is not to avoid an exception, since splice and join on empty arrays just returns an empty string. It's rather for you to be able to raise an error or something if needed. So if the array has values, I keep the first two positions with splice(0,2) and then join that array with a '.'. I recommend it more than the substr method you were going for because what if you get a number that's 191.0.0.1 then the substr would return the wrong string back, but with splice and join that would never happen.
Things to improve
I would strongly suggest using more human comprehensible variables (reflect their use in the code)
The right path for prop value checking is through Prop.Types, super easy to use, very helpful.
Happy coding!

Categories

Resources