Writing indexOf function in JavaScript - javascript

I am new to JavaScript. I have created a indexof function in but it is not giving the correct output:
Question is:
/*
Implement a function called indexOf that accepts two parameters: a string and a character, and returns the first index of character in the string.
*/
This is my code:
function indexOf(string, character) {
let result = string;
let i = 0;
let output = 1;
while (i < result.length) {
if (result[i] === character) {
output = output + indexOf[i];
}
}
return output;
}
I want to know what i am doing wrong. Please Help.

You are making things a little harder than you need to. If you want to do this without calling the built-in indexOf(), which I assume is the point of the exercise, you just need to return from the function as soon as your condition matches. The instructions say "return the first index" — that's the i in your loop.
If you make it through the loop without finding something it's traditional to return -1:
function indexOf(string, character) {
let i=0;
while(i < string.length){
if(string[i] == character){ // yes? just return the index i
return i
}
i++ // no? increase i and move on to next loop iteration
}
return -1; // made it through the loop and without returning. This means no match was found.
}
console.log(indexOf("Mark Was Here", "M"))
console.log(indexOf("Mark Was Here", "W"))
console.log(indexOf("Mark Was Here", "X"))

Assuming from your question that the exercise is to only match the first occurrence of a character and not a substring (multiple characters in a row), then the most direct way to do it is the following:
const indexOf = (word, character) => {
for (let i = 0; i < word.length; i++) {
if (word[i] === character) {
return i;
}
}
return -1;
}
If you also need to match substrings, leave a comment on this answer if you can't figure it out and I'll help you along.

indexOf() is a built in method for strings that tells you the index of a particular character in a word. Note that this will always return the index of the FIRST matching character.-
You can write something like:
function indexOf(string, character){
return string.indexOf(character)
}
So if I were to use my function and pass in the two required arguments:
indexOf("woof", "o") //this would return 1

Related

How to check if a string only contains chars from an array?

I try to check if a word (wordToCheck) only consists of letters from an array (letters) and also contains every letter in the array only as often (or rather not more times than they are in the array) as it actually is inside of the array.
Here are examples of what the desired function should return:
checkIfWordContainsLetters("google", ["a","o","o","g","g","l","e","x"]) === true
checkIfWordContainsLetters("google", ["a","o","g","g","l","e","x"]) === false
How can I make this code work?
function checkIfWordContainsLetters(wordToCheck, letters) {
var lettersToString = letters.toString();
var lettersTrimmed = lettersToString.replace(/,/gi, "?");
var regEx = new RegExp(lettersTrimmed, "gi");
if (wordToCheck.match(regEx)!== null) {
return true;
}
else return false;
}
You could use this ES6 function:
function checkIfWordContainsLetters(wordToCheck, letters){
return !letters.reduce((a, b) => a.replace(b,''), wordToCheck.toLowerCase()).length;
}
console.log(checkIfWordContainsLetters("google", ["a","o","o","g","g","l","e","x"]));
console.log(checkIfWordContainsLetters("google", ["a","o","g","g","l","e","x"]));
The idea is to go through each letter in the letters array, and remove one (not more!) occurrence of it in the given wordToCheck argument (well, not exactly in it, but taking a copy that lacks that one character). If after making these removals there are still characters left over, the return value is false -- true otherwise.
Of course, if you use Internet Explorer, you won't have the necessary ES6 support. This is the ES5-compatible code:
function checkIfWordContainsLetters(wordToCheck, letters){
return !letters.reduce(function (a, b) {
return a.replace(b, '');
}, wordToCheck.toLowerCase()).length;
}
console.log(checkIfWordContainsLetters("google", ["a","o","o","g","g","l","e","x"]));
console.log(checkIfWordContainsLetters("google", ["a","o","g","g","l","e","x"]));
As long as it is not the best solution for long strings for which using some clever regex is definitely better, it works for short ones without whitespaces.
function checkIfWordContainsLetters(word, letters){
word = word.toLowerCase().split('');
for(var i = 0; i < letters.length; i++) {
var index = word.indexOf( letters[i].toLowerCase() );
if( index !== -1 ) {
// if word contains that letter, remove it
word.splice( index , 1 );
// if words length is 0, return true
if( !word.length ) return true;
}
}
return false;
}
checkIfWordContainsLetters("google", ["a","o","o","g","g","l","e","x"]); // returns true
checkIfWordContainsLetters("google", ["a","o","g","g","l","e","x"]); // returns false

How can I rewrite the .length() property using slice()?

This is my assignment:
By now you should have worked with the length property of strings, e.g. "hello".length. Your task is to write a function called stringLength that accepts a string as a parameter and computes the length of that string; however, as you may have guessed, you are not allowed to use the length property of the string!
Instead, you'll need to make use of the string method called slice.
For our purposes, we can consider slice as taking one argument -- the index to begin slicing from, and returns a new string starting from that index onwards.
This is what I tried:
function stringLength(string){
var count = count++;
if(string.slice(0)){
return count}
return stringLength(string.slice(0,-1))
}
console.log(stringLength("game"))
I am trying to slice each character of the string back to start index, index 0, and then accumulate my count variable. I do not understand why my count variable is not accumulating.
An iterative proposal.
function stringLength(string) {
var count = 0;
while (string) {
string = string.slice(1);
count++;
}
return count;
}
console.log(stringLength("game"));
A recursive proposal.
function stringLength(string) {
return string ? 1 + stringLength(string.slice(1)) : 0;
}
console.log(stringLength("game"));
Hmm i tried to write code in the same format that you did.
function stringLength(str, count){
if(!str.slice(0)){
return count;
}
return stringLength(str.slice(0,-1), ++count)
}
console.log(stringLength("game", 0))
I'll point out the mistakes in your original code so that its easy to understand.
The recursion base case was incorrect. string.slice(0) will return
true if the string is non-empty, so use !string.slice(0)
The count value was not initialized and it wasn't being passed down
the recursion.
Your count variable is a separate variable for each function invocation, so it will always get the same value and not keep incrementing.
You could use this:
function stringLength(string){
return string ? 1 + stringLength(string.slice(0,-1)) : 0;
}
console.log(stringLength("game"))
A bit shorter would be to take out the first character instead of the last:
return string ? 1 + stringLength(string.slice(1)) : 0;
You really should try to figure it out yourself. Otherwise, are you really learning the subject?
function stringLength(string) {
if(!string) return 0;
var length = -1;
while(string.slice(length) !== string) --length;
return -length;
}
A variation taking into account your odd definition of slice():
function stringLength(string) {
var length = 0;
while(string.slice(length) !== "") ++length;
return length;
}
I guess you could try to use recursion like this:
function stringLength(string) {
if (string) {
return 1 + stringLength(string.slice(1))
} else return 0
}
function stringLength(string) {
var len = 0;
while (string) {
string = string.substring(1);
len++;
}
return len;
}
console.log(stringLength("boss"));
this works as well.

How to remove spaces and special characters from string?

I have a function that returns true if a character is a form of punctuation and I'm trying to write another function that accepts a string and removes the spaces and punctuation marks while calling the first function. I got most of it I think. But now I'm stuck. Any help is appreciated.
var isPunct = function(ch) {
if (ch = ch.match(/[,.!?;:'-]/g))
return true
else
return false
}
//B
var compress = function(s) {
var result = "";
//loop to traverse s
for (var i = 0; i < s.length; i++) {
if (!(isPunct(ch));
//(isPunct(s.charAt(i) || s.charAt(i) == " "));
//do nothing
else
result = result + !compress(i)
}
return result
}
Some issues:
The inner condition should in fact be the opposite: you want to do nothing when it is a punctuation character, i.e. you don't want to add it to the result. Only in the other case you want to do that.
The call !compress(i) is wrong: first of all that function expects a string, not an index, and it returns a string, not a boolean (so to perform ! on it). It seems like you want to call your function recursively, and although that is an option, you are also iterating over the string. You should do one of the two: recursion or iteration.
You reference a variable ch in the compress function which you have not defined there.
So, if you want to write compress the iteration way, change your code as follows:
var compress = function(s) {
var result = "", ch; // define ch.
//loop to traverse s
for (var i = 0; i < s.length; i++) {
ch = s[i]; // initialise ch.
if (!isPunct(ch)) result = result + ch; // only add when not punctuation
}
return result;
}
If on the other hand you want to keep your recursive call to compress, then you should do away with your for loop:
var compress = function(s) {
var result = "", ch, rest;
if (s.length == 0) return '';
result = compress(s.substr(1)); // recursive call
ch = s[0];
if (!isPunct(ch)) result = ch + result;
return result;
}
The function isPunct also has a strange thing happening: it assigns a boolean value to ch in the if expression. This does not make your function malfunction, but that assignment serves no purpose: the match method already returns the boolean you need for your if condition.
It is also not really nice-looking to first evaluate a boolean expression in an if to then return that same value in the form of false and true. This you can do by just returning the evaluated expression itself:
var isPunct = function(ch) {
return ch.match(/[,.!?;:'-]/g);
}
On a final note, you don't really need the isPunct function if you only use it in compress. The whole logic can be performed in one function only, like this:
let compress = s => s.replace(/[,.!?;:'-]/g,'');
// Demo:
console.log(compress('a,b,c')); // abc
If you prefer to keep isPunct and don't want to repeat the regular expression elsewhere, then you can do the replace like this:
let isPunct = ch => ch.match(/[,.!?;:'-]/g);
let compress = s => Array.from(s).filter(ch => !isPunct(ch)).join('');
// Demo:
console.log(compress('a,b,c')); // abc
Note how the use of ES6 arrow functions and ES5 Array methods makes the code quite lean.

Using indexOf() to compare characters in an Array

function mutation(arr) {
var tester = arr[1].split('');
for (var i = 0; i < tester.length; i ++) {
if (!arr[0].indexOf(tester[i])) return false;
}
return true;
}
mutation(["hello", "hey"]);
Here I should return true 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.
I do not see any problems with this code but it passes like only 90% of the tests and I do not know why. And I can not see a pattern there — what exact conditions should I meet to fail the test.
The indexOf() method returns the index within the calling String
object of the first occurrence of the specified value, starting the
search at fromIndex. Returns -1 if the value is not found.
String.prototype.indexOf() returns -1 if value was't found, that is why your statement doesn't work.
Change to:
if (arr[0].indexOf(tester[i]) < 0) return false;
This won't work because you are classing the first position (0 position) as not acceptable.
Your condition will only be true for values which aren't greater than 0, when 0 should also be valid.
Therefore change it so that it only returns false for values which are less than 0.
Change this line:
if (!arr[0].indexOf(tester[i])) return false;
To:
if (arr[0].indexOf(tester[i]) < 0) return false;
Things were really obvious — Upper/LowerCase() issue. This works now:
function mutation(arr) {
arr[0] = arr[0].toLowerCase();
arr[1] = arr[1].toLowerCase();
var tester = arr[1].split('');
for (var i = 0; i < tester.length; i ++) {
if (arr[0].indexOf(tester[i]) == -1) return false;
}
return true;
}
mutation(["hello", "hey"]);
And of course I have not noticed an obvious 0 position issue:
if (arr[0].indexOf(tester[i]) == -1) return false;
^ this is correct.
Thanks everyone!

Recursion with names

I'm a little lost in general, but if someone could please briefly explain why this code works that would be great!
// Our array of messy words
var capitals = ["berlin", "parIs", "MaDRiD"];
// Capitalize function
function capitalize(word) {
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
}
// Our recursive function
function fixLetterCase(array, i) {
// Base case
if (i === array.length) {
return;
}
// Action
array[i] = capitalize(array[i]);
// Recursive case
return fixLetterCase(array, i + 1);
}
// Here is our function call
fixLetterCase(capitals, 0);
console.log(capitals);
While I understand this is not an answer to the question, I thought it might help to see a non-recursive version of the logic:
// Our array of messy words
var capitals = ["berlin", "parIs", "MaDRiD"];
// Simple function to capitalize word
function fixLetterCase(array) {
for(var i = 0; i < array.length; i++) {
array[i] = array[i].charAt(0).toUpperCase() + array[i].slice(1).toLowerCase();
}
}
fixLetterCase(capitals);
console.log(capitals);​
Here's a working fiddle to play with.
function fixLetterCase(array, i) {
// At some point, this is true, so the algorithm stops
if (i === array.length) { return; }
// At this point, the function did not returned. The function logic continues.
// Replace the array key with a new value = the return value of captialize()
array[i] = capitalize(array[i]);
// i increments by one, and the function itself is called again.
return fixLetterCase(array, i + 1);
}
// Initialize the function, with starting offset ("counter") i=0
fixLetterCase(capitals, 0);
// Our recursive function
function fixLetterCase(array) {
for (var i = 0, length = array.length; i < length; i++) {
array[i] = capitalize(array[i]);
}
}
Would probably be a better, more readable, more performant solution. This case does not need recursion at all, a loop should be more effective. You don't need that many function calls and you don't need to evaluate the array's length with every function call.
I assume you're talking about the recursive part. It's really just an exotic way to iterate over the array.
Conventionally you might do this with a for loop, following the pattern (forgive the totally weird pseudo-code, my own gross invention):
for ([initialization]; [condition]; [modification])
[function]
With recursion you can do it as:
[function [initialization]]
if [!condition]
break
[function [modification]]
I personally feel there's not much benefit to the recursive version in this case, as it's much less idiomatic and thus less obvious how it works; and it offers no performance benefit.
The function fixLetterCase is called with i equal to zero. When fixLetterCase runs for the first time, it calls capitalize on the first word in the array. In the recursive call, it increments i with 1 so that means it will capitalize the next word in the array. It will keep doing this until it reaches the end of the array.
That's why the function works: the index of the word that needs to be capitalized is incremented each time and in the last call, when the index is equal to the length of the array, the 'recursion' ends.
Note that this is not a typical use of recursion because there's nothing returned from the recursive calls. Also note that this could be written much more straightforwardly as a for loop.
This really doesn't need to be written recursivly, you could do the same thing with
// Our array of messy words
var capitals = ["berlin", "parIs", "MaDRiD"];
// Capitalize function
function capitalize(word) {
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
}
// Our recursive function
function fixLetterCase(array, i) {
// Action
array[i] = capitalize(array[i]);
}
// Here is our function call
for(var i = 0; i < capitals.length; i++)
{
fixLetterCase(capitals, i);
}
console.log(capitals);
The recursive part is only iterating through the capital words and escapes when you reach the end of the array. Hopefully reading it like this will make it more clear.

Categories