When to use 'i' vs. 'str[i]'? - javascript

why does using 'i' in the if statement return different results than using 'str[i]'?
function ExOh(str) {
xCount = 0;
oCount = 0;
for (var i=0;i<str.length;i++){
if (str[i]=='x') {
xCount++;
} else if (str[i]=='o') {
oCount++;
}
}
if (xCount==oCount) {
return true;
} else {
return false;
}
}
console.log(ExOh("xox"));

i returns the current value of the same in the for loop: for (var i=0;i<str.length;i++)
And, str[i] returns the character in the string str at the i'th position.
So, although the value of i is the same inside the if or for loop, the actual values of i and str[i] will be different.
Readup:
for | MDN
array | MDN

In this case, i refers to the index of a character in the string str, and when you use str[i] you are accessing the character of str at index i. For example, take the following string:
var str = "My string";
The string str has 9 characters, and each index, from 0 to 8, will refer to a specific character within it. Thus, str[0] = "M", str[1] = "y", etc. Here, 0 and 1 are indexes, while "M" and "y" are characters at such indexes.

why does using 'i' in the if statement return different results than using 'str[i]'?
I in this case is an integer indicating the place (index) within an array. Where is str[i] is the item within that place.

i refers to the position or index of a character (beginning at 0), so in this case i refers to the index of a character in the string. It will return a number.
str[i] refers to the exact character of that string, not its position or index, so it will return a non-number, unless that character in the string happens to be a number.

Related

issue with substring indexing

Instructions for this kata:
In this Kata, we will check if a string contains consecutive letters as they appear in the English alphabet and if each letter occurs only once.
It seems that my code is indexing the strings differently per function call on this one. for example, on the first test "abcd", the starting index is shown as 0, which is correct, and on the second example, "himjlk", the
var subString = alphabet.substring(startIndex, length);
returns "g", instead of "h"
troubleshooting this section
var length = orderedString.length;
//startChar for string comparison
var startChar = orderedString.charAt(0);
//find index in aphabet of first character in orderedString.
var startIndex = alphabet.indexOf(startChar);
//create substring of alphabet with start index of orderedString and //orderedString.length
var subString = alphabet.substring(startIndex, length);
function solve(s) {
//alphabet string to check against
const alphabet = `abcdefghijklmnopqrstuvwxyz`;
//check s against alphabet
//empty array to order input string
var ordered = [];
//iterate through alphabet, checking against s
//and reorder input string to be alphabetized
for (var z in alphabet) {
var charToCheck = alphabet[z];
for (var i in s) {
if (charToCheck === s[i]) {
ordered.push(s[i]);
}
//break out of loop if lengths are the same
if (ordered.length === s.length) {
break;
}
}
if (ordered.length === s.length) {
break;
}
}
//join array back into string
var orderedString = ordered.join(``);
//length for future alphabet substring for comparison
var length = orderedString.length;
//startChar for string comparison
var startChar = orderedString.charAt(0);
//find index in aphabet of first character in orderedString.
var startIndex = alphabet.indexOf(startChar);
//create substring of alphabet with start index of orderedString and orderedString.length
var subString = alphabet.substring(startIndex, length);
//return if the two are a match
return subString == orderedString ? true : false;
}
console.log(solve("abdc")); //expected `true`
console.log(solve("himjlk")); // expected `true`
console.log(solve("abdc")); should provide the substring "abcd" and return true, which it does.
console.log(solve("himjlk")); should put together "hijklm" and return true, but instead gives me g based on index 6 of alphabet, not sure why it's doing this, should be index 7 "h" returns false based upon this error.
The problem is that you're using substring() instead of substr(). Though that might sound similar there's a difference.
With substring the second parameter doesn't determine the length as you might have expected. It's actually the index to stop.
That your function works as expected with the string abcd is pure coincidence since in this case the length from index 0 and the end index are the same.
function solve(s){
const alphabet = `abcdefghijklmnopqrstuvwxyz`;
var ordered = [];
for(var z in alphabet){
var charToCheck = alphabet[z];
for(var i in s){
if(charToCheck === s[i]){
ordered.push(s[i]);
}
if(ordered.length === s.length){ break; }
}
if(ordered.length === s.length){ break; }
}
var orderedString = ordered.join(``);
var length = orderedString.length;
var startChar = orderedString.charAt(0);
var startIndex = alphabet.indexOf(startChar);
var subString = alphabet.substr(startIndex, length);
return subString == orderedString ? true: false;
}
console.log(solve("himjlk"));
You approach is also correct. I am giving another solution using sort() and charCodeAt. Instead of getting the index and then breaking string into parts to compare just use includes()
function check(str){
let org = [...Array(26)].map((x,i) => String.fromCharCode(i + 97)).join('');
str = str.split('').sort((a, b) => a.charCodeAt(0) - b.charCodeAt(0)).join('');
return org.includes(str);
}
console.log(check("abdc"))//true
console.log(check("himjlk"));//true
console.log(check("himjlkp"));//false
Explanation:
Frist Line:
let org = [...Array(26)].map((x,i) => String.fromCharCode(i + 97)).join('');
is use to create string "abcd....xyz".
[...Array(26)] will create an array of 26(no of alphabets) undefined values.
map() is a function which takes a callback and the create an array based the values of previous. The first parameter of map() callback x is the value itself which will be undefined(because all the values in array are undefined).
i the second parameter will be the index of the element. Which will start from 0 upto 25.
String.fromCharCode is function which takes a character code(integer) and then convert it to string. For example character code for a is 97 so String.fromCharCode(97) will return "a". 98 for "b", 99 for "c" etc.
So after map() an array like ["a","b"....,"z"] will be generated.
-join() will convert that to string
Second Line:
str is given string. str.split('') will convert string to array. For example
if str is "abdc" it will return ["a","b","d","c"]
sort() is the array method which takes the callback. The two parameters are two values to be compared during sort(). a and b are two values.
charCodeAt acts in reverse as String.fromCharCode. For example "a".charCodeAt(0) will be return 97 for "b" it will 98 and so on.
a.charCodeAt(0) - b.charCodeAt(0) which is returned from sort() will sort array is ascending order. And join() will convert array to string.
So string "abdc" will become "abcd"
Third Line:
The third line is the main one. org is string "abcdefghijklmnopqrstuvwxyz". Now if any string is a substring of this string then it means its in alphabetical order. So we check the sorted str is includes in the string or not.
You can clean up the second line by
str = str.split('').sort().join('');
Because if no callback is passed to sort() it will sort in default order. Mean alphabetical order.

Regex for alternating indexes from a word boundary

I've just finished this programming challenge on CodeWars:
Write a function toWeirdCase that accepts a string, and returns the same string with all even indexed characters in each word upper cased, and all odd indexed characters in each word lower cased. The indexing just explained is zero based, so the zero-ith index is even, therefore that character should be upper cased.
I tried to figure this out with regex before giving up and simply using a for loop with indexes. Just to confirm, the index of capitalising letters resets to 0 whenever there is a space. So ThIs Is A CoRrEcT AnSwEr but ThIs iS nOt, because every first letter of each word must be capitalised.
With that in mind, is there an approach to look for alternate (odd or even) indexes using regex? In this case, find a word boundary using \b, and then every even index from there, until the end of the word?
You can borrow map to convert apply a function to each character, i%2 to detect if i is odd, and toLowerCase or toUpperCase to change the case:
function toWeirdCase(str) {
return [].map.call(str, function(char, i) {
return char[i%2 ? 'toLowerCase' : 'toUpperCase']();
}).join('');
}
There are multiple ways to reset the index at each space. For example,
function toWeirdCase(str) {
var i = 0;
return [].map.call(str, function(char) {
if(char === ' ') i = -1;
return char[i++ % 2 ? 'toLowerCase' : 'toUpperCase']();
}).join('');
}
The function parameter to replace receives the match offset after the matched string and matched groups.
function toWeirdCase(s) {
return s.replace(/[a-zA-Z]/g, function (ltr, offset) {
return offset & 1 ? ltr.toLowerCase() : ltr.toUpperCase();
});
}
You need to split the input into words, then weird case each word:
function toWeirdCase(str) {
return str.split(' ').map(weirdCaseWord).join(' ');
}
weirdCaseWord can be written as in the other answer:
function weirdCaseWord(str) {
return str.split('').map(function(char, i) {
return char[i%2 ? 'toLowerCase' : 'toUpperCase']();
}).join('');
}
If you prefer, you could use a single map with a flag which is toggled on each character, and reset on a space:
function toWeirdCase(str) {
var even = false;
return str.split('').map(function(char) {
even = char === ' ' ? false : !even;
return char[even ? 'toUpperCase' : 'toLowerCase']();
}).join('');
}

Trouble with Javascript easy coderbyte challenge

I'm attempting to answer this question:
Using the JavaScript language, have the function SimpleSymbols(str) take the str parameter being passed and determine if it is an acceptable sequence by either returning the string true or false. The str parameter will be composed of + and = symbols with several letters between them (ie. ++d+===+c++==a) and for the string to be true each letter must be surrounded by a + symbol. So the string to the left would be false. The string will not be empty and will have at least one letter.
Here's my solution:
function SimpleSymbols(str) {
var test;
for (var i =0; i<str.length; i++){
if ((str.charAt(i)!== '+' && str.charAt(i+1) === str.match(/[a-z]/))
||(str.charAt(i+1) === str.match(/[a-z]/) && str.charAt(i+2) !== '+')){
test = false;
break;
}
else if (str.charAt(0) === str.match(/[a-z]/)){
test = false;
break;}
else {
test= true;}
}
return test;
};
I think you can just use two regex and then compare the length of arrays returned by them
function SimpleSymbols(str){
return str.match(/[a-z]/g).length == str.match(/\+[a-z]\+/g).length;
}
The first regex /[a-z]/g will match all the letters and /\+[a-z]\+/g will match all the letters which are followed and preceded by a literal +.
Then, we just use the Array.length property to check if the lengths are same or not and then return the Boolean result. As simple as that.

traverse a string char by char javascript

function SimpleSymbols(str) {
var letter =['a','b','c','d','e','f','g','h','i','j',
'k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'];
var newstr = "";
for (var i = 0; i<str.length; i++){
if (str.charAt(i).toLowerCase() in letter){
newstr += "M";
}
else{
newstr += "X";
}
}
return newstr;
}
If str is "Argument goes here" it returns XXXXXXXXX. WHy doesn't it return MMMMMMMMMM?
you do not look up an entry in an array with in. use indexOf() to find the position of an array entry. indexOf() will return the position or -1 if no entry is found.
for (var i = 0; i<str.length; i++){
var strChar = str.charAt(i).toLowerCase();
if ( letter.indexOf(strChar) >= 0 ) {
newstr += "M";
}
…
The in operator returns true if the object has a property with that name, not with that value.
An array is basically an object with numeric properties. I.e. the indexes are the property names of the object. It basically looks like this:
var letters = {
0: 'a',
1: 'b',
...
length: ...
};
So in your case the condition will only be true if str.charAt(i).toLowerCase() returns a number between 0 and letter.length (and since charAt only returns one character, it can only be 0-9).
Example:
> var letters = ['a', 'b', 'c'];
> 'a' in letters // array doesn't have a property 'a'
false
> 0 in letters // array has a property 0 (it's the first element)
true
So since, "Argument goes here" doesn't contain any digits, the in condition will always be false and that's why you get XXXXXX... as result.
See the question "How do I check if an array includes an object in JavaScript?" for testing the existence of an element in an array.
FWIW, to make the in operator work, you would have to create an object of the form:
var letters = {
'a': true,
'b': true,
// ...
};
but that's a bit cumbersome to write.
Allow me to offer a side view, another way handle what I think you intent to do by using Regular Expressions with something like:
"test2".replace(/[a-z]/gi,"M").replace(/[^M]/g,"X") //Outputs "MMMMX"
String.replace will replace an string that contains letters from [a-z] the i at the end of the expression means case insensitive. g means will search for all possible matches and not just the first match. In the second expression [^M] this ^ means negation so anything that is not an M will be replaced with X.
There is another way in which we implement a custom function within the String.replace using Regular Expressions and it can be implemented like this:
"test2".replace(/([a-z])|([^a-z])/gi,
function(m,g1, g2){
return g1 ? "M" : "X";
});
In regular expression parenthesis creates groups and | means or in this expression ([a-z])|([^a-z]) there 2 groups one with letters from a-z and the other which means everything that is not a-z with the replace function we asked only for group g1 if it is group 1 is M otherwise is an X.
Another cool thing you could do is add this function to all your string by prototyping it like:
String.prototype.traverse = function(){ return this.replace(/([a-z])|([^a-z])/gi,function(m,g1){ return g1 ? "M" : "X" });}
Then it can be used as simple as: "test1".traverse();

Find multiple fragments of string in a string

I have a string of IDs in CSV format in an input box
12,23,26,32
I have to check if this string contains 23 or 24, if yes then return false, else return true
Use indexOf. You can check if it contains a subString. If not found, it returns -1
var str = "12,23,26,32"
return !(str.indexOf("23")!=-1 || str.indexOf("24")!=-1) // Dont have 23 or 24
=======EDIT=======
Like #Matt said in comment, this solution will work also to "12,239,26,32" and thats not the point.
Make the split before check the indexOf, then you will get the element between the commas.
var array = "12,23,26,32".split(",");
return !(array.indexOf("23")!=-1 || array.indexOf("24")!=-1) // Dont have 23 or 24
!/(^|,)2[34](,|$)/.test( str );
or if there may be whitespace present
!/(^|,)\s*2[34]\s*(,|$)/.test( str );
The RegExp test method returns true if the string argument matches the regular expression or false if it doesn't. The ! inverts the result of the test call.
^ is the metacharacter for the start of the string, so(^|,) means either 'at the start of the string' or 'one comma character'.
It can't be written [^,] as that would mean 'one character that isn't a comma', and it can't be written [,^] as that means 'one character that is either a comma or a literal ^ character.
2[34] means 2 followed by 3 or 4.
(,|$) means a comma or the end $ of the string.
\s* means zero or more space characters.
if (/(?:^|,)(23|24)(?:,|$)/.test("12,23,26,32")) {
/* found 23 or 24 */
}
Try this
var str = "12,23,26,32";
var isFound = (str.indexOf('23') || str.indexOf('24')) > -1;
var str = "12,23,26,32";
var obj = str.split(",");
var isFound = false;
for(i=0; i < obj.length; i++)
{
if(obj[i] == "23" || obj[i] == "24")
{
isFound = true;
break;
}
}
return isFound;

Categories

Resources