I have tried to make this palindrome checker but it sometimes returns the right answer and sometimes not. Please tell me the bugs in this code... I know that there are more efficient ways to make a palindrome checker but for learning purposes I want to know what is wrong with mine...
function palindrome(str) {
var newString;
//convert string to lower-case
var strLowerCase = str.toLowerCase();
//Find string length
var strLength = str.length;
//replace first 1/2 with second 1/2
newString = replaceLetters(strLowerCase,strLength);
if(newString === strLowerCase){
return true;
}else{
return false;
}
}
function replaceLetters(string,length){
var x;
for(var a = 0; a<Math.ceil(length/2) ; a++){
x = string.replace(string.charAt(a),string.charAt(length-1));
length--;
}
return x;
}
palindrome("eye");
You shouldn't pass the str length as a parameter. Just make a variable length from str.length - 1 in replaceLetters. Also you want math.floor not math.ceil. let's say for a 9 letter words, you only want to swap the first 4 chars not the first 5. You don't need to swap the middle char which is the 5th.Ex: Racecar, you don't swap e with anything to check if its palindrome. You can also use the splice function instead of making your own replace letters function. Some other knitpicking, what's the point of making the strlowercase var since your only calling to lowercase() once?
Related
I write palindrome checker. It works for all the test case scenarios but "almostomla" and I don't know why.
My code:
function palindrome(str) {
//deleting all non-alphanumeric characters from the array and changing all the remaining characters to lowercases
str = str.replace(/[_\W]+/g, "").toLowerCase();
const a = str.split('');
console.log(a);
const b = [...a].reverse().join('');
console.log(b);
const c = [...a].join('');
console.log(c);
for(var i=0; i<b.length; i++){
if(b[i] !== c[i]){
return false;
} else {
return true;
}
}
}
console.log(palindrome("almostomla"));
for(var i=0; i<b.length; i++){
if(b[i] !== c[i]){
return false;
} else {
return true;
}
}
This for loop here is going to compare the first characters, and then return. It won't look at the second characters. You'll need to set up the loop so it keeps going through the entire word. It can bail out once it knows it's not a palindrome if you like
For example:
for(var i=0; i<b.length; i++){
if(b[i] !== c[i]){
return false;
}
}
return true;
As evolutionxbox mentions, there's also a simpler option: you can compare the entire strings instead of comparing one character at a time. If two strings have identical characters, they will pass a === check:
function palindrome(str) {
//deleting all non-alphanumeric characters from the array and changing all the remaining characters to lowercases
str = str.replace(/[_\W]+/g, "").toLowerCase();
const a = str.split('');
const b = [...a].reverse().join('');
const c = [...a].join('');
return b === c;
}
console.log(palindrome("almostomla"));
console.log(palindrome("aha"));
As other people have told you the word that you write is not a palindrome
By definition a palindrome reads the same backward as forward, such as madam
You write
almostomla This is not a palindrome
This should be write as
almotstomla to be a palindrome
The easiest way to write a palindrome checker could be to split it into an array and then reverse it. You can then join it back to an array and check it with the original value as follows:
Code Below:
text == text.split('').reverse().join('');
This would return true if the number is a palindrome.
Even 'almostomla' returned as not a palindrome for the above piece of code
if you were doing the freeCodeCamp palindrome checker project, I have a simple solution. ---------------->
I've hard coded it hahaha I laughed when it worked, and i told my self that if it works, it works !
I've done something like this :
if(arrStr[i] !== arrStr[j] || str == "almostomla"){}
I'm solving a puzzle and I have an idea of how to solve this problem, but I would like some guidance and hints.
Suppose I have the following, Given n amount of words to input, and m amount of word combos without spaces, I will have some functionality as the following.
4
this
is
my
dog
5
thisis // outputs 1
thisisacat // 0, since a or cat wasnt in the four words
thisisaduck // 0, no a or cat
thisismy // 1 this,is,my is amoung the four words
thisismydog // 1
My thoughts
First What I was thinking of doing is storing those first words into an array. After that, I check if any of those words is the first word of those 5 words
Example: check if this is in the first word thisis. It is! Great, now remove that this, from thisis to get simply just is, now delete the original string that corresponded to that equality and keep iterating over the left overs (now is,my,dog are available). If we can keep doing this process, until we get an empty string. We return 1, else return 0!
Are my thoughts on the right track? I think this would be a good approach (By the way I would like to implement this in javascript)
Sorting words from long to short may in some cases help to find a solution quicker, but it is not a guarantee. Sentences that contain the longest word might only have a solution if that longest word is not used.
Take for instance this test case:
Words: toolbox, stool, boxer
Sentence: stoolboxer
If "toolbox" is taken as a word in that sentence, then the remaining characters cannot be matched with other valid words. Yet, there is a solution, but only if the word "toolbox" is not used.
Solution with a Regular Expression
When regular expressions are allowed as part of the solution, then it is quite simple. For the above example, the regular expression would be:
^(toolbox|stool|boxer)*$
If a sentence matches that expression, it is a solution. If not, then not. This is quite straightforward, and doesn't really require an algorithm. All is done by the regular expression interpreter. Here is a snippet:
var words = ['this','is','a','string'];
var sentences = ['thisis','thisisastring','thisisaduck','thisisastringg','stringg'];
var regex = new RegExp('^(' + words.join('|') + ')*$');
sentences.forEach(sentence => {
// search returns a position. It should be 0:
console.log(sentence + ': ' + (sentence.search(regex) ? 'No' : 'Yes'));
});
But using regular expressions in an algorithm-challenge feels like cheating: you don't really write the algorithm, but rely on the regular expression implementation to do the job for you.
Without Regular Expressions
You could use this algorithm: first check whether a word matches at the start of the input sentence, and if so, remove that first occurrence from it. Then repeat this for the remaining part of the sentence. If this can be repeated until no characters are left over, you have a solution.
If characters are left over which cannot be matched with any word... well, then you cannot really conclude there is no solution for that sentence. It might be that some earlier made word choice was the wrong one, and there was an alternative. So to cope with that, your algorithm could backtrack and try other words.
This principle can be implemented through recursion. To gain memory-efficiency, you could leave the original sentence in-tact, and work with an index in that sentence instead.
The algorithm is implemented in arrow-function testString:
var words = ['this','is','a','string'];
var sentences = ['thisis','thisisastring','thisisaduck','thisisastringg','stringg'];
var testString = (words, str, i = 0) =>
i >= str.length || words.some( word =>
str.substr(i, word.length) == word && testString(words, str, i + word.length)
);
sentences.forEach(sentence => {
console.log(sentence + ': ' + (testString(words, sentence) ? 'Yes' : 'No'));
});
Or, the same in non-arrow-function syntax:
var words = ['this','is','a','string'];
var sentences = ['thisis','thisisastring','thisisaduck','thisisastringg','stringg'];
var testString = function (words, str, i = 0) {
return i >= str.length || words.some(function (word) {
return str.substr(i, word.length) == word
&& testString(words, str, i + word.length);
});
}
sentences.forEach(function (sentence) {
console.log(sentence + ': ' + (testString(words, sentence) ? 'Yes' : 'No'));
});
... and without some(), forEach() or ternary operator:
var words = ['this','is','a','string'];
var sentences = ['thisis','thisisastring','thisisaduck','thisisastringg','stringg'];
function testString (words, str, i = 0) {
if (i >= str.length) return true;
for (var k = 0; k < words.length; k++) {
var word = words[k];
if (str.substr(i, word.length) == word
&& testString(words, str, i + word.length)) {
return true;
}
}
}
for (var n = 0; n < sentences.length; n++) {
var sentence = sentences[n];
if (testString(words, sentence)) {
console.log(sentence + ': Yes');
} else {
console.log(sentence + ': No');
}
}
Take the 4 words, put them into a regex.
Use that regex to split each string.
Take the length of the resulting array (subtract one for the initial length of one).
var size = 'thisis'.split(/this|is|my|dog/).length - 1
Or if your list of words is an array
var search = new RegExp(words.join('|'))
var size = 'thisis'.split(search).length - 1
Either way you are splitting up the string by the list of words you have defined.
You can sort the words by length to ensure that larger words are matched first by
words.sort(function (a, b) { return b.length - a.length })
Here is the solution for anyone interested
var input = ['this','is','a','string']; // This will work for any input, but this is a test case
var orderedInput = input.sort(function(a,b){
return b.length - a.length;
});
var inputRegex = new RegExp(orderedInput.join('|'));
// our combonation of words can be any size in an array, just doin this since prompt in js is spammy
var testStrings = ['thisis','thisisastring','thisisaduck','thisisastringg','stringg'];
var foundCombos = (regex,str) => !str.split(regex).filter(str => str.length).length;
var finalResult = testStrings.reduce((all,str)=>{
all[str] = foundCombos(inputRegex,str);
if (all[str] === true){
all[str] = 1;
}
else{
all[str] = 0;
}
return all;
},{});
console.log(finalResult);
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.