Just for exercising with indexOf() method and to have a better familiarity with how it works and what can be done with it, I desire to print the index for each character in a phrase, one by one.
I could do it successfully manually, this way:
// Print index for char of phrase (case insensitive):
let phrase = "ab";
alert(phrase.indexOf("a")); // 0
alert(phrase.indexOf("b")); // 1
alert(phrase.indexOf("z")); // -1
But when I tried to use a loop, I failed:
// Print char by index:
let phrase = "ab";
for (let i = -1; i < phrase.indexOf(); i++) {
alert(phrase.length[i]);
}
I also tried with regex to target each character inside phrase but also failed:
let phrase = "ab";
for (let i = -1; i < phrase.indexOf(/./); i++) {
alert(phrase.length[i]);
}
To clarify, my aim is to have a first alert with 0, and the second with 1. I just want to print the index of each character, instead the character length, as can easily be done with:
phrase.length // 2.
How could I print the index of each character in separate alerts?
It is super important for me to use indexOf() inside a loop to know this syntax.
You could do it this way :
for(let i=0; i<phrase.length; i++) {
console.log(phrase.indexOf(phrase[i]));
}
Don't use indexOf. You use this method to get the position (index) of a certain character in the string:
A string has a length property and can be iterated:
let phrase = "aaabbbaaaabbb"
function getAllIndices(stringInput) {
for (let i = 0; i < stringInput.length; i++) {
//you simply need to output i.
console.log(stringInput[i] + " > " + i);
}
}
getAllIndices(phrase);
While not always the case: the most common format for a for loop is:
for (let i = 0; i < someVariable.length; i++) { //...some code }
And indeed that's what you want here.
It means:
start at i being 0 (i = 0)
Do whatever is in my body (// ...some code)
increase i by 1 (i++)
Repeat, until i is equal to one less than the length of someVariable (someVariable.length) *
* That last step may seem kinda confusing. Remember: indices start at 0, but length count, well, counts normal - so starting at 1. So an string of length 3, say 'c'+'a'+'t'. is made up of characters at indices [0, 1, 2]. Sooo you want the loop, to stop at that last index - 2 - which is (always) one less that the length. (But honestly, this is overexplaining it. The short answer is: if you wanna loop through something - 99 times out of 100 you want that exact for loop format given up top.
So to look at your example: we wanna fix three things:
We want to have let i = 0; (remember it doesn't increment until it's run once
We want to say i < phrase.length; (i < phrase.indexOf() doesn't mean anything. phrase.indexOf() is a function, not a number.)
phrase.length means "tell me the length of the variable phrase." It just returns a number. (So phrase.length[i] doesn't mean anything). If you want to alert whatever letter is at this index, it's just phrase[i]. *
* If this syntax for getting a letter by just putting [#] after strings seems weird - well that's because it was more designed for arrays . If you have let arr = ['a', 'b', 'c'], then sure, I could see why the JavaScript devs said "let's make a quick way to get, oh, the value at index 2 of an array. How about just arr[2]? But for consistency, they said "yeah sure, let's give this ability to strings to." And if you think about it, a string is sort of just an array of letters.
Update: I just noticed you wanted the index of each letter, not the letter itselt. Well...technically you could just alert(i) then. That's it, that's the index. But if you wanted to know what letter we're talking about, I would do something like alert("Letter " + phrase[i] + " is at index " + i)
So our final answer is:
let phrase = "ab";
for (let i = 0; i < phrase.length; i++) {
alert("Letter " + phrase[i] + " is at index " + i)
}
It is super important for me to use indexOf() inside a loop to know this syntax.
You would never use indexOf() for something like this. It would not just be unnecessary, it would be wrong. If you had the string banana and tried to use indexOf() to (re)check each letters position, you would get 0,1,2,1,2,1. Why? Because indexOf() only returns the index of the first instance of that letter.
indexOf() is not something you'd likely pair with a for loop - at least not a for loop searching the same string. It is a loop itself. It's job is to prevent you from having to write a for loop to find the index of "b" in "ab". It will do it for you.
To print the index of each character in a loop you don't need indexOf()
let phrase = "ab";
for (let i = 0; i < phrase.length; i++) {
alert (i);
}
because i is the exact index you need.
In fact if you use indexOf() in a loop, that's what it looks like :
let phrase = "ab";
for (let i = 0; i < phrase.length; i++) {
alert (phrase.indexOf (phrase[i]));
}
Same result as before, but this time, instead of displaying i, you retrieve the current element in phrase and use indexOf() to get the already known index.
EDIT : indexOf() in this case work as expected because letters in phrase are different. But as SamVK said if let phrase = "banana";, it can't work because it will return always 1 for letter 'a' so you must not use it for that kind of loop.
I did not use let i = -1 because it is not an index of phrase. It is just what indexOf() returns if it can't find the element given.
I hope it helps.
If you absolutely want to use indexOf in a loop, you could do so :
let phrase = "ab";
Array.from(phrase).forEach(char => {
console.log(phrase.indexOf(char))
})
But this is pretty useless as there are simpler ways to accomplish this but since it looks like it is for a learning purpose, I hope this answer helps you!
Related
I was asked this question in a recent interview. I need to find the longest substring without repeating characters.
Given "abcabcbb", the answer is "abc", which the length is 3.
Given "bbbbb", the answer is "b", with the length of 1.
Given "pwwkew", the answer is "wke", with the length of 3
This is what I came up with, I think it works correctly, but the interviewer was not impressed and said that my solution may not work for all cases.
var str = "pwwkew";
var longSubstring = function(str) {
var obj = {}; //map object
var count = 0;
var c = []; //count array to keep the count so far
for (var i = 0; i < str.length; ++i) {
//check if the letter is already in the map
if (str[i] in obj && obj[str[i]] !== i) {
c.push(count); //we encountered repeat character, so save the count
obj = {};
obj[str[i]] = i;
count = 1;
continue;
} else {
obj[str[i]] = i;
++count;
}
}
return Math.max.apply(null, c);
}
console.log(longSubstring(str)); //prints 3
Can anyone tell me what's the problem with my solution? I think it is one of the best :) and also solves in O(n) time.
I guess the problem with your code is, it gets haywire when there is no repeating letters in the whole sentence to start with. As mentioned in one of the comments "abc" won't produce a correct result. My approach would be slightly different than yours as follows;
var str = "pwwkew",
data = Array.prototype.reduce.call(str, (p,c) => (p.test.includes(c) ? p.test = [c]
: p.test.length >= p.last.length ? p.test = p.last = p.test.concat(c)
: p.test.push(c)
, p), {last:[], test:[]}),
result = data.last.length;
console.log(data);
console.log(result);
In this reduce code we initially start with an object like {last:[], test:[]} and go over the characters one by one. If the received character is in our objects's test array we immediately reset the test array to include only the letter we tested (the p.test = [c] line). However If the received character is not in our test array then we do either one of the two thing as follows. If our test array's length is equal or longer than the last array's length then we add the current character to test array and make last array = test array. (p.test.length >= p.last.length ? p.test = p.last = p.test.concat(c) line). But if our test array's length is shorter than the last array's length we just add the current character to test array and continue likewise all the way to the end of the string one by one over single characters.
I'm working through a problem on freecodecamp.com, and I want to see whether my code so far is doing what I think it is doing...
function titleCase(str) {
var wordArr = str.split(' '); // now the sentences is an array of words
for (var i = 0; i < wordArr.length; i++) { //looping through the words now...
charArr = wordArr[i].split(''); //charArr is a 2D array of characters within words?
return charArr[1][1];
}
}
titleCase("a little tea pot"); // this should give me 'i', right?
Again, this is just the beginning of the code. My goal is to capitalize the first letter of each word in the parameter of titleCase();. Perhaps I'm not even going about this right at all.
But... is charArr on line 4 a multidimensional array. Did that create [['a'],['l','i','t','t','l','e'],['t','e','a','p','o','t']]?
In addition to ABR answer (I can't comment yet) :
charArr is a one-dimensional array, if you want it to be a 2d array you need to push the result of wordArr[i].split(''); instead of assigning it.
charArr.push(wordArr[i].split(''));
And don't forget to initialize charArr as an empty array
Few issues :
1. Your return statement will stop this after one iteration.
2. If one of the words have fewer then 2 letters (like the first one in your example, which is 'a') - you will get an exception at charArr[1][1].
Other then that, it is mostly ok.
It would probably help you to download a tool like firebug and test your code live...
You can do the following:
function titleCase(str) {
var newString = "";
var wordArr = str.split(' ');
for (var i = 0; i < wordArr.length; i++) { //looping through the words now...
var firstLetter = wordArr[i].slice(0,1); // get the first letter
//capitalize the first letter and attach the rest of the word
newString += firstLetter.toUpperCase() + wordArr[i].substring(1) + " ";
}
return newString;
}
Also you need to remove the return statement in your for loop because the first time the for loop goes over the return statement, it will end the function and you will not be able to loop through all the words
Here you can learn more about string.slice() : http://www.w3schools.com/jsref/jsref_slice_string.asp
I'm writing a JavaScript function that has to take in a string argument & determine the word or words with the maximum number or repeated (or most frequent) non sequential characters and return that word or words.
The way that I went about solving this problem was to first find the maximum number of times a character was repeated per word and record that number to use later in a function to test against every word in the string (or the array of strings as I later split it); if the word met the conditions, it's pushed into an array that I return.
My maxCount function seemed to work fine on its own but when I try to make it work together with my other function to get the words with max repeated chars returned, it's not working in JS Fiddle - it keeps telling me that "string.split is not a function" - I'll admit that the way I'm using it (string.split(string[i]).length) to analyze words in the string letter by letter is a bit unconventional - I hope there's some way to salvage some of my logic to make this work in the functions that can work together to get the results that I want.
Also, I don't know if I'm using Math.max correctly/in a "legal" way, I hope so. I've tried switching my variable name to "string" thinking that would make a difference but it did not even though my arguments are of the string variety and it's a string that's being represented.
Here's a link to my Fiddle:
https://jsfiddle.net/Tamara6666/rdwxqoh6/
Here's my code:
var maxCount = function (word) {
/// var maxRepeats = 0;
var numArray = [];
var string = word;
for (var i = 0, len = string.length; i < len; i++) {
//split the word('string') into letters at the index of i
numArray.push((string.split(string[i]).length) -1);
}
var max = Math.max(...numArray);
return max;
}
///console.log(maxCount("xxxxxxxxxxxxx"));
var LetterCount = function(string){
var repeatedChars = 0;
var wordArray=[];
var stringArray = string.split(" ");
for (var i = 0; i < stringArray.length; i++){
var eachWord = stringArray[i];
var maxRepeats = maxCount(stringArray);
if (repeatedChars < maxRepeats) {
repeatedChars = maxRepeats;
wordArray = [eachWord];
}else if (repeatedChars == maxRepeats) {
wordArray.push(eachWord);
}
}
return wordArray;
};
console.log(LetterCount("I attribute my success to cats"));
//should return ["attribute", "success"]
*** I've tried to map this first function onto the array formed when I split my string at the spaces but it is just returned me an empty array (I also might not have been using map correctly in this example); I also have tried using valueOf to extract the primitive value out of the array from the first function which also didn't work. I'm not really sure what to do at this point or what angle to take- I feel if I understood more what was going wrong I could more easily go about fixing it. Any help would be much appreciated. Thanks!
You are passing an array to maxCount at line 20, while it expects a string:
var maxRepeats = maxCount(stringArray);
You should use:
var maxRepeats = maxCount(eachWord);
If you are getting split is not a function error then first make sure that your string isn't null by printing it on console. If it isn't null then confirm that its a string not an array or some other thing.
Lets say I have a string, but the text could be anything!
This is a test case
The 'boundary' is the count after a space, this means the charIndex =
(0) This
(5) is
(8) a
(10) test
(15) case
The above means from (0) to (5) the word equals 'this '.
If I wanted to know the word just used, I would need to substr start at charIndex and look backwards until indexOf(' ')
Example: If I wanted to find the word just used at charIndex (10) how would I instruct javascript to look backwards until the next space and give me the word "a ".
Is it possible to do this, with as little process time, using Javascript, or JQuery?
UPDATE
Instead of looking after the word and going back, I decided to achieve what I needed, I split the words and used each charIndex as a count. Code follows:
var u = new SpeechSynthesisUtterance();
var words = element.innerHTML.split(' ');
var a = 0;
u.text = element.innerHTML;
u.lang = 'en-UK';
u.rate = 0.7;
u.onboundary = function(event) {
console.log(words);
element.innerHTML = element.innerHTML.replace(words[a], '<strong>' + words[a] + '</strong>');
a++;
}
But as this is not the questions answer, still the best answer to reverse search a string is that which is marked correct, although it still needs some work depending on the string structure.
Not clear about exact question but you can use a combination of lastindexof, indexof and substr in your case or write your own stuff.
Note: No error handling etc. is being done. Please do that.
var stringToBeParsed="This is a test case"
i = stringToBeParsed.lastIndexOf(" ",8);
j = stringToBeParsed.indexOf(" ",i+1);
document.getElementById('output').innerText = stringToBeParsed.substr(i,j-i);
Custom
function parseBackward(stringToBeParsed, indexOfSpace){
var output = '';
for (var i = indexOfSpace-1; i >= 0; i--) {
if(stringToBeParsed.charAt(i) == ' '){
break;
}
output = stringToBeParsed.charAt(i) + output;
}
document.getElementById('output').innerText = output;
}
If I understand your question you can use lastIndexOf:
var TC="This is a test case"
TC.lastIndexOf(" ",10)
This will return 9, using lastIndexOf(string,position) searches backwards.
EDIT:
If you need the word:
var TC="This is a test case"
TC.substr(TC.lastIndexOf(' ',10)+1,TC.length - TC.indexOf(' ',10));
So you use substr. First search backwards from position 10 space (and sum 1 to get on the beginning of letter) to start the substr. As second parameter y get the next occurrence and substract to length.
EDIT2:
Ok this functions works is supposed to work in less than milisecond:
function getWord(phrase,position){
var last = phrase.indexOf(' ',position);
var more=0
if (last == -1){
more = phrase.length;
} else { more = phrase.indexOf(' ',position);}
var word = phrase.substring(phrase.lastIndexOf(' ',position)+1,more);
return(word);
}
In this plunkr http://plnkr.co/wfeitWvSvoLzqIknKFyg you can check how it takes less than a milisecond to work. And if you open a console you will see how it take the word at position specified.
I'm toying around with Javascript and I now want to extract all pairs of consecutive characters from a string. So if the string is "test" I want to output "te", "es" and "st". Now I found out how to extract single letters from a string, by treating the string as an array, and using the "in" keyword as follows:
var str = 'this is a test';
//report letters
for (var t in str) {
var c = str[t];
console.log(t + ': ' + c);
}
This seems to work. The console logs suggest that t is an index. So I figure I should be able to use t + 1 as the index for the next character in str. However, my guesses don't seem to work, when trying the following:
//report letterpairs
for (var t in str) {
var c = str[t] + str[t + 1];
console.log(t + ': ' + c);
}
This reports str[t + 1] as being "undefined".
//report letterpairs
for (var t in str) {
var c = str.substring(t, t + 1);
console.log(t + ': ' + c);
}
This returns the first character when t = 0; but a much longer substring when t = 1, and the t-th up to the last character when t >= 2.
Now I assume I can probably use a "normal" for loop using
for (t = 0; t < str.length; t += 1) {
}
but firstly I prefer the cleanness of the "in" keyword and want to learn how to use the "in" keyword because I'm not familiar with it from other languages. And secondly, I'd like to know why the methods above using the "in" keyword do not work. Where's the error in my line of thought?
That's not a good use-case for JavaScript's for...in loop. That loop type actually loops over the keys of an object. Because all keys in JavaScript are strings, t is always a string. Thus, t + 1 is also a string - and the + is string concatenation, not a sum.
What you really want to do is a normal for loop, counting indexes (this also lets you stop early so you don't try to get the last character and the character after it):
for(var i = 0;i < str.length - 1;i++) {
var c = str[i] + str[i+1];
console.log(t + ": " + c);
}
For Arrays and Strings you should stick with the normal for loop, not for...in.
The problem is that t is a string, so t + 1 is also a string. The method substring then behaves in a different way than the one you expect when t + 1 is given. If you put str.substring(parseInt(t), parseInt(t) + 2); it gives a result similar to the one you expect (there are better ways to do this). The difference is that the last one is 3: t as there are no more characters.
I would prefer to use the for(var t = 0; t < str.length - 1; t++) in this case.
For-in in javascript is a bit special, it enumerates the attributes of an object and might give some unexpected results.
Have a look at: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in
One of the problems you encounter is your indexer is going out of bounds because of the x+1 (in the last loop cycle you go outside of the array).
For arrays you better stick with a regular for-loop, or you could use some nice array helper methods offered by some of the frameworks (jQuery for instance).