Why indexOf in javascript not working? - javascript

I'm not sure what I'm doing wrong here. The first instance that I use indexOf it works perfectly fine, but when I use it the second time it's not returning the result that I'm expecting.
function mutation(arr) {
//return arr;
res = "";
for (var x=0; x<arr[1].split("").length; x++) {
if (arr[0].indexOf(arr[1].split("")[x]) !== -1) {
res += "t";
} else {
res += "f";
}
}
// res = ttt
if (res.indexOf("f") !== -1) {
return true;
} else {
return false;
}
}
mutation(["hello", "hey"]);
// this returns true instead of false
mutation(["floor", "loo"]);
// returns false instead of true
mutation should return false if an element from arr[1] is not present in arr[0] else return true.

your code isn't working because when you say:
res.indexOf("f") != -1
this means: "I found an f", but you're treating it as if it means "I did not find an f".
In your case that you want to return false if you find an 'f', but you're returning true. Flip your true and false cases:
if (res.indexOf("f") != -1) {
return false;
} else {
return true;
}
ALSO your for loop is wrong because x starts at 0, so you need to go to < length not <= length of your string.
for (var x=0; x < arr[1].split("").length; x++) {
and now your code works as you wanted it to.

Just edited your code. Click on the <p> to check:
function mutation(arr) {
//return arr;
res = "";
for (var x=0; x< arr[1].split("").length; x++) {
res += arr[0].indexOf(arr[1].split("")[x]) > -1 ? 't' : 'f';
}
return res.indexOf('f') > -1;
}
$('p').click(function(){
alert(mutation(["hello", "hey"]));
alert(mutation(["floor", "loo"]));
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Click me</p>

If you simplify the logic a bit, that's easier to check:
function mutation(arr) {
return arr[1].split('').reduce(function(res, x) {
return arr[0].indexOf(x) >= 0;
}, true);
}
Thanks Leon for the correction.

I tried to not chance your logic, the mistake are:
You're trying to compare with all characters on the array[0], not only the first.
If you find a character equals on the first character on array[0] you should return true.
Correct code:
function mutation(arr) {
res = "";
for (var x=0; x<=arr[1].split("").length; x++) {
if (arr[0].split("")[0].indexOf(arr[1].split("")[x]) !== -1) {
return true;
}
}
return false;
}

Related

Return "True" if all the characters in a string are "x" or "X" else return false

I am looking at this code challenge:
Complete the function isAllX to determine if the entire string is made of lower-case x or upper-case X. Return true if they are, false if not.
Examples:
isAllX("Xx"); // true
isAllX("xAbX"); // false
Below is my answer, but it is wrong. I want "false" for the complete string if any of the character is not "x" or "X":
function isAllX(string) {
for (let i = 0; i < string.length; i++) {
if (string[i] === "x" || string[i] === "X") {
console.log(true);
} else if (string[i] !== "x" || string[i] !== "X") {
console.log(false);
}
}
}
isAllX("xAbX");
Your loop is outputting a result in every iteration. There are two issues with that:
You should only give one result for an input, so not in every iteration; currently you are reporting on every single character in the input string.
You are asked to return a boolean result (false/true), not to have the function print something. That should be left to the caller
You could take a simpler approach though, and first turn the input string to all lower case. Now you only have to look for "x". Then take out all "x" and see if something is left over. You can check the length property of the resulting string to decide whether the return value should be false or true:
function isAllX(string) {
return string.toLowerCase().replaceAll("x", "").length == 0;
}
console.log(isAllX("xxXXxxAxx")); // false
console.log(isAllX("xxXXxxXxx")); // true
If you are confortable with regular expressions, you could also use the test method:
function isAllX(string) {
return /^x*$/i.test(string);
}
console.log(isAllX("xxXXxxAxx")); // false
console.log(isAllX("xxXXxxXxx")); // true
You can try this way.
function isAllX(str) {
let isX = true;
let newString = str.toLowerCase();
for (let i = 0; i < newString.length; i++) {
if (newString[i] !== "x") {
isX = false;
}
}
return isX;
}
console.log(isAllX("xAbX"));
console.log(isAllX("XXXxxxXXXxxx"));
You can use regex to find the same.
function allX(testString) {
return /^x+$/i.test(testString);
}
console.log(allX("xxXX"));
console.log(allX("xxAAAXX"));
Without any method if you want
function isAllX(str) {
let flag = true;
for (let i = 0; i < str.length; i++) {
if (str[i] !== "x" && str[i] !== "X") {
flag = false;
// break;
}
}
return flag;
}
console.log(isAllX("xAbX"));
console.log(isAllX("XXXxxxXXXxxx"));
console.log(isAllX("xx"));
You can try converting the string to a single case, then looping over it while checking for the condition as below
function isAllX(string) {
const newString = string.toUpperCase();
for (let i = 0; i < newString.length; i++) {
if (newString[i] !== "X") {
return false
}
}return true
}

Check if string exists in another string (not exactly equal)

I have this 2 strings:
var test = 'BN123';
var behaviour = 'BN***,TA****';
I need to check if behaviour contains a string with the same format as test.
On the behaviour, the BN and TA as to be equal, and the * means it can be any char. (behaviour comes from an API, so I never know what it has, this is just a test.)
In this case it should return true. Right now I'm only comparing is case behaviour as a single string, but I need to modify that:
isValidInput(behaviour, test) {
if (behaviour.length != test.length) {
return false;
}
for (var i = 0; i < behaviour.length; i++) {
if (behaviour.charAt(i) == '*') {
continue;
}
if (behaviour.charAt(i) != test.charAt(i)) {
return false;
}
}
return true;
}
You can use .some() of Array.prototype.
like below
function isValidInput(behaviour, string1) {
if (behaviour.length != string1.length) {
return false;
}
for (var i = 0; i < behaviour.length; i++) {
if (behaviour.charAt(i) == '*') {
continue;
}
if (behaviour.charAt(i) != string1.charAt(i)) {
return false;
}
}
return true;
}
var test = 'BN123';
var behaviour = 'BN***,TA****';
console.log(behaviour.split(',').some(x => isValidInput(x,test)));
console.log(behaviour.split(',').some(x => isValidInput(x,"test")));
The only issue I see with your implementation is that you're not allowing for the fact behaviour contains possible strings separated with a comma (or at least, that's how it looks to me). So you need to check each of them:
// Check one behaviour string from the list
function isOneValidInput(behaviour, string) {
if (behaviour.length != string.length) {
return false;
}
for (var i = 0; i < behaviour.length; i++) {
// Note we can easily combine those conditions, and use []
// with strings
if (behaviour[i] != '*' && behaviour[i] != string[i]) {
return false;
}
}
return true;
}
// Check all behaviour strings in a comma-separated one
function isValidInput(behaviours, string) {
return behaviours.split(",").some(function(behaviour) {
return isOneValidInput(behaviour, string);
});
}
var string = 'BN123';
var behaviour = 'BN***,TA****';
console.log(isValidInput(behaviour, string));
(I stuck to ES5 there because you seemed to be doing so.)
Is this what you want?
var test = 'BN123';
var behaviour = 'BN***,TA****';
var behaviours = behaviour.split(',');
var result = behaviours.map(b => {
if (b.length != test.length)
return false;
var pattern = b.split('*')[0];
return pattern === test.substring(0,pattern.length);
}).find(r => r === true) > -1;
console.log(result)
You can use the new .includes() method to see if a string is contained within another. Note that this is case sensitive. I have included two dodgied up behaviours to check the string against.
var string = 'BN123';
var behaviour1 = 'BN123,TA1234';
var behaviour2 = 'BN120,TA1230';
function testStr(behaviour,string) {
return behaviour.includes(string);
}
console.log(testStr(behaviour1,string)) // gives true
console.log(testStr(behaviour2,string)) // gives false
isValidInput(behaviour, string) {
var array = behaviour.split(",");
var flag = 0;
for(var i = 0;i< array.length;i++){
var now = array[i];
var _flag = 1;
if (now.length == string.length) {
for (var j = 0; j < now.length; j++) {
if (now.charAt(j) == '*') {
continue;
}
if (now.charAt(j) != string.charAt(j)) {
_flag = 0;
}
}
flag |= _flag;
}
}
return flag;
}
Try modify your behaviour to RegExp:
function checkFn(testStr) {
var behaviour = '(BN...)|(TA....)'
var r = new RegExp('^(' + behaviour + ')$')
return r.test(testStr)
}
checkFn('BN123') // true
checkFn('BN12') // false
checkFn('BN1234') // false
checkFn('TA1234') // true
checkFn('TA123') // false
checkFn('TA12345') // false
Or use this fn:
function checkFn(testStr) {
var behaviour = 'BN***,TA****'
behaviour = behaviour
.split(',')
.reduce((r, el) => {
r.push('(' + el.replace(/\*/g, '.') + ')')
return r
}, [])
.join('|')
var r = new RegExp('^('+behaviour+')$')
return r.test(testStr)
}

Why is my while loop not iterating through completely?

So this is my code below, the goal is for this program is to check to see if the letters of the second string can be found in the first string. However I found the problem that i isn't, increasing in value. So the loop is only going through once. So this program ends at the first letter that it finds and returns true. How do I get i to increase so that it's iterating through every character of the string?
function mutation(arr) {
var str = arr[1];
str = str.toLowerCase().split("");
var i = 0;
while (i < arr.length) {
if (arr[0].indexOf(str[i]) > -1) {
//return arr[i].indexOf(str[i], i);
return true;
} else {
return false;
}
i++;
}
}
mutation(["hello", "hey"]);
This maybe?
function mutation(arr) {
var str = arr[1];
str = str.toLowerCase().split("");
// iterating an array screams "for loop"
for (var i=0; i < str.length; i++) {
// if the letter was not found exit immediately
if (arr[0].indexOf(str[i]) == -1) return false;
}
// since it didn't exit before, all the letters must have been found.
return true;
}
function mutation(arr) {
var base = arr[0],
str = arr[1].toLowerCase().split(''),
i = 0,
match = true;
while (i < str.length) {
// if any target letter is not in base, return false
if(base.indexOf(str[i]) === -1){
return false;
}
}
// otherwise they were all in, so return true
return true;
}
mutation(["hello", "hey"]);
Totally different technique.
This function replaces, in the second string, all letters from the first string with empty space. If the length is zero all letters were found.
function mutation(arr) {
return arr[1].replace(new RegExp("[" + arr[0] + "]", "g"), "").length == 0;
}

Cannot read property length null error when used with regular expressions

I'm a javascript beginner doing some CodeWars.com questions. I came across this question and I'm stuck due to a "cannot read property length null" error. I've tried to look up that error and can't find what the problem is in my program.
The assignment is:
"Check to see if a string has the same amount of 'x's and 'o's. The method must return a boolean and be case insensitive. The string can contains any char."
And this is what I've written so far:
function XO(str) {
var x = "x";
var o = "o";
var numX = str.match(/x/gi).length;
var numO = str.match(/o/gi).length;
while(str.indexOf(x) > -1 || str.indexOf(o) > -1) {
if(numX == numO){
return true;
}
}
if (numX === -1 && numO === -1){
return true;
}
}
XO("xoxo");
The assignment also says that if there is neither an X or an O then the program should return true.
This will not give you that error. When there are no matches, the match function returns null and you cannot get the length of null. A few extra lines solves this issue.
function XO(str) {
var x = "x";
var o = "o";
var numX = 0;
var numO = 0;
var xMatch = str.match(/x/gi);
var oMatch = str.match(/o/gi);
if (xMatch) {
numX = xMatch.length;
}
if (oMatch) {
numO = oMatch.length;
}
while(str.indexOf(x) > -1 || str.indexOf(o) > -1) {
if(numX == numO){
return true;
} else {
return false;
}
}
if (numX === -1 && numO === -1){
return true;
} else {
return false;
}
}
console.log(XO("ddd"));
I think you are making this problem more complex than it has to be.
All you need to do is make the string lowercase(to account for case insensitive), traverse the string, and when it finds an x, add 1 to a counter, and when you find and o, decrease 1 from the counter.
If it ends at 0, you return true, else you return false. There's no need for regexes
function XO(str){
var count = 0;
str = str.toLowerCase();
for(var i = 0; i < str.length; i++){
if(str[i] === 'x') count++;
if(str[i] === 'o') count--;
}
return count === 0 ? true : false;
}
Yes you have to check the return value of match is not null before checking the length property. However
while(str.indexOf(x) > -1 || str.indexOf(o) > -1) {
if(numX == numO){
return true;
}
}
looks like an infinite loop if either string contains lower case 'x' or 'o' and there are a different number of each.
More simply:
function XO(str)
{ var matchX = str.match(/x/gi);
var matchY = str.match(/o/gi);
return (matchX && matchY) ? matchX.length == matchY.length : !matchX && !matchY;
}

checking strings in an array

I'm trying to see if the string in the first element of the array contains all of the letters of the string in the second element of the array.
For example
['hello', 'hey'] = false;
['Army', 'Mary'] = true;
Here is my code
function mutation(arr) {
a = arr[0].toLowerCase().split("");
b = arr[1].toLowerCase().split("");
for(i = 0; i < a.length; i++){
if(b.indexOf(a[i]) != -1){
console.log('true');
} else {
console.log('false');
}
}
}
mutation(['Army', 'Mary']);
UPDATED
I need to see if element 1 contains all the letters for element 2 before I return back anything.
This would do, I'm sure there are better and optimal solutions though,
1) Storing the return result in a boolean, as var result = true;.
2) Check if both the Strings are equal/same, no need to loop, return the result which is true.
3) loop through each characters and see if the target element contains them, if found a mismatch set, result to false, break and return result.
function mutation(arr) {
a = arr[0].toLowerCase().split("");
b = arr[1].toLowerCase().split("");
var result = true;
if(a === b)
return result;
for(i = 0; i < a.length; i++){
if(b.indexOf(a[i]) === -1){
result = false;
break;
}
}
return result;
}
mutation(['Army', 'Mary']);
UPDATE Added a condition if (a === b) return true; to skip for loop.
No need of loop, you can take advantage of array functions.
Steps
Sort both arrays
Cast to the string
Check if strings2 contains string1
function mutation(arr) {
var a = arr[0].toLowerCase().split(''),
b = arr[1].toLowerCase().split('');
// For exact equality
return a.sort().toString() === b.sort().toString();
// return b.sort().toString().indexOf(a.sort().toString()) > -1;
}
document.write('Army and Mary: ' + mutation(['Army', 'Mary'])); // true
document.write('<br />a and b: ' + mutation(['a', 'b'])); // false
document.write('<br />ab and abc: ' + mutation(['ab', 'abc'])); // false
Simply you need to loop throught the second element letters and return false if a character doesn't exist in first element, or continue the loop if it exists.
Then check if the counter is equal to your string length then it contains all the given letters and return true:
function mutation(arr) {
a = arr[1].toLowerCase().split("");
b = arr[0].toLowerCase().split("");
if (a === b) return true;
for (i = 0; i < a.length; i++) {
if (b.indexOf(a[i]) === -1) {
return false;
}
}
if (i === a.length) {
return true; // all the letteers of element one exists in the second element
}
}
if (mutation(['Army', 'Mary'])) {
alert("Element one contains all letters of second element !");
} else {
alert("Sorry!");
}
Note:
Make sure you loop throught the second element characters and not the first one, see the a = arr[1].toLowerCase().split("");.
//mutation function work ignoring case and order of character in strings
function mutation(arr) {
var first = arr[0].toLowerCase();
var second = arr[1].toLowerCase();
for(var i = 0; i < second.length; i++){
if(first.indexOf(second[i]) == -1){
return false;
}
}
return true;
}
//this returns true
mutation(["hello", "ol"]);

Categories

Resources