More efficient palindrome code - javascript

This is a code I used for the coderbyte challenge "Palindrome". The challenge is to return true if str is the same foward and backward(a palindrome). I got all possible points but I know my code is a little ugly. What would be a more efficient way to write this code. It looks like I am repeating myself and it seems like something that could maybe be written with a for loop.I also see how it could return true when its really false if there was a longer palindrome without the use of a for loop:
function Palindrome(str) {
var low=str.toLowerCase()
var first = low.charAt(0);
var last = low.charAt(low.length-1);
var mid = low.charAt(1);
var mid1 = low.charAt(low.length-2);
if(first===last)
if(mid===mid1)
{
return true
}
else
{
return false
}
else
{
return false
}
}
print(Palindrome(readline()));

To check the string if it's a palindrome you just should compare it to its reversed version.
Say the word hello is not a palndrome because its reversed version olleh is not equal to it. But the word eye is a palindrome same as word abba because they're equal to their reversed versions.
Code example:
(function() {
var reverseStr,
isPalindrome,
testStrings;
reverseStr = function(str) {
var chars = [];
for(var i = str.length - 1; i > -1; i--) {
chars.push(str[i]);
}
return chars.join('');
};
isPalindrome = function(str, ignoreCase) {
if(ignoreCase) {
str = str.toLowerCase();
}
return str === reverseStr(str);
};
testStrings = ['abba', 'hello', 'eye'];
for(var i = 0, l = testStrings.length; i < l; i++) {
var word = testStrings[i];
console.log('Word "%s" is %sa palindrome',
word,
isPalindrome(word) ? '' : 'not ');
}
})();
DEMO #1
Another way that could work faster is listed below. Here you don't receive a reversed string to compare but walking towards the middle of the string from its start and its end.
var isPalindrome = function(str, ignoreCase) {
var length,
last,
halfLength,
i;
if(ignoreCase) {
str = str.toLowerCase();
}
length = str.length;
last = length - 1;
halfLength = Math.ceil(length / 2);
for(i = 0; i < halfLength; i++) {
if(str[i] !== str[last - i]) {
return false;
}
}
return true;
};
DEMO #2

function Palindrome(str) {
str = str.toLowerCase();
str = str.split(" ").join("");
return str == str.split("").reverse().join("");
}
This is what I ended up with. Made sure the string was all lowercase so it wouldn't read a potentially true parameter as false, got rid of the spaces, and then returned true/false based off whether or not the string was equal to it's reverse.

Here is an even easier way:
var isPalindrome = function(string) {
string = string.toLowerCase();
if(string.length===0){
return false;
}
for (var i = 0; i < Math.ceil(string.length/2); i++) {
var j = string.length-1-i;
var character1 = string.charAt(i);
var character2 = string.charAt(j);
if (character1 !== character2) {
return false;
}
}
return true;
};

I came across this palindrome coding challenge with a twist, you have to replace all the non-alphanumeric characters(punctuation, spaces and symbols) and of course change the string into lowercase. This is my solution.
function palindrome(str) {
var low = str.toLowerCase();
var filteredStr = low.replace(/[^0-9a-z]/gi, "");
var split = filteredStr.split("");
var backward = split.reverse();
var join = backward.join("");
if (filteredStr === join) {
return true;
} else {
return false;
}
}
if you care about number of lines of code, here's smaller one
function palindrome(str) {
var low = str.toLowerCase();
var filteredStr = low.replace(/[^0-9a-z]/gi, "");
var backward = filteredStr.split("").reverse().join("");
if (filteredStr === backward) {
return true;
} else {
return false;
}
}
the code is beginner friendly and self explanatory, but if you have any questions regarding the code, feel free to ask ;)

Related

Palindrome Checker need a hand

I'm working on freeCodeCamp's Palindrome Checker. My code is a bit messy but it pretty works on every test except the nineth one. palindrome("almostomla") should return false but in my code it returns trueinstead. I think my nineth code has a little problem but couldn't solve that. I wonder where am I missing something.
function palindrome(str) {
let str1 = str.replace(/[^a-zA-Z\d:]/gi, '');
let str2 = str1.replace(/,/gi, '');
let str3 = str2.replace(/\./gi, '');
let str4 = str3.replace(/_/, "-");
let myStr = str4.toLowerCase(); //My string is ready for play
for (let i = 0; i < myStr.length; i++) {
if (myStr[i] != myStr[myStr.length - (i+1)]) { //I think there is a little mistake on this line
return false;
} else {
return true;
}
}
The problem is that you're only checking the first and last characters of the string. You should return true only after all iterations have finished:
function palindrome(str) {
let str1 = str.replace(/[^a-zA-Z\d:]/gi, '');
let str2 = str1.replace(/,/gi, '');
let str3 = str2.replace(/\./gi, '');
let str4 = str3.replace(/_/, "-");
let myStr = str4.toLowerCase(); //My string is ready for play
for (let i = 0; i < myStr.length; i++) {
if (myStr[i] != myStr[myStr.length - (i + 1)]) {
return false;
}
}
return true;
}
console.log(palindrome("almostomla"));
console.log(palindrome("foof"));
console.log(palindrome("fobof"));
console.log(palindrome("fobbf"));
Note that your initial regular expression is sufficient - it removes all characters that aren't alphabetical, numeric, or :, so the other 3 regular expressions you run later are superfluous. Since you're using the i flag, you can also remove the A-Z from the regex:
const stringToTest = str.replace(/[^a-z\d:]/gi, '');
It would also probably be easier just to .reverse() the string:
function palindrome(str) {
const strToTest = str.replace(/[^a-z\d:]/gi, '');
return strToTest.split('').reverse().join('') === strToTest;
}
console.log(palindrome("almostomla"));
console.log(palindrome("foof"));
console.log(palindrome("fobof"));
console.log(palindrome("fobbf"));

Reducing duplicate characters in a string to a given minimum

I was messing around with the first question here: Reduce duplicate characters to a desired minimum and am looking for more elegant answers than what I came up with. It passes the test but curious to see other solutions. The sample tests are:
reduceString('aaaabbbb', 2) 'aabb'
reduceString('xaaabbbb', 2) 'xaabb'
reduceString('aaaabbbb', 1) 'ab'
reduceString('aaxxxaabbbb', 2) 'aaxxaabb'
and my solution (that passes these tests):
reduceString = function(str, amount) {
var count = 0;
var result = '';
for (var i = 0; i < str.length; i++) {
if (str[i] === str[i+1]) {
count++;
if (count < amount) {
result += str[i];
}
} else {
count = 0;
result += str[i];
}
};
return result;
}
Just use regular expressions.
var reduceString = function (str, amount) {
var re = new RegExp("(.)(?=\\1{" + amount + "})","g");
return str.replace(re, "");
}
I guess my best solution would be like
var str = "axxxaabbbbcaaxxxaab",
redStr = (s,n) => s.replace(/(\w)\1+/g,"$1".repeat(n));
console.log(redStr(str,2));
I tried to make it as short as possible:
reduceString = function(str, amount) {
var finalString = '', cL = '', counter;
str.split('').forEach(function(i){
if (i !== cL) counter = 0;
counter++;
cL = i;
if (counter <= amount ) finalString = finalString + i;
});
return finalString;
}
You can use reg expression instead. tested in javascript.
how it works:
(.) //match any character
\1 //if it follow by the same character
+{2 //more than 1 times
/g //global
$1 //is 1 time by $1$1 is 2 times
reduceString('aaaabbbb', 2)
reduceString('xaaabbbb', 2)
reduceString('aaaabbbb', 1)
reduceString('aaxxxaabbbb', 2)
function reduceString(txt,num)
{
var canRepeat=['$1'];
for (i=1;i<num;i++)
{
canRepeat.push('$1')
}
canRepeat = canRepeat.join('');
console.log(txt.replace(/(.)\1{2,}/g, canRepeat))
}
With regex:
var reduceString = function(str, amount) {
var x = [ ...new Set(str) ];
for (var c of x){
var rex = new RegExp(c + '{'+amount+',}','g');
str = str.replace(rex,string(c,amount));
}
return str;
};
var string = function(c,amount){
for(var i=0,s="";i<amount;i++)s+=c;
return s;
};
Up above regex solutions are much more better, but here is my accepted solution with reduce:
make an array from string via spread operator
Check the previous item
find how many times char is repeated in result string
otherwise concat result string with the current char
Don`t forget to use the second argument as the initial value, and return for each cases
reduceString = function(str, amount) {
return [...str].reduce(((res, cur)=>{
if(res.length && cur === res[res.length-1]){
dupsCount = [...res].filter(char => char === cur).length
if(dupsCount===amount){
return res;
}
else {
res+=cur;
return res;
}
}
res+=cur;
return res;
}),"")
}

Palindrome Program avoiding spaces, punctuation in Javascript

I'm trying to make a palindrome program using javascript that will show if a string is palindrome or not by TRUE or FALSE even if the string has punctuation and spaces(ex- madam, i'm adam). But everytime I put a string I only get TRUE no matter what the string is. Here is my code,
function isPalindrome (str) {
var nopunctuation = str.replace(/[\.,-\/#!$%\^&\*;:{}=\-_`~()]/g,"");
var nospaces = nopunctuation.replace(/\s/g,"");
var finalstring = nospaces;
var len = finalstring.length;
for ( var i = 0; i < Math.floor(finalstring/2); i++ ) {
if (finalstring[i] !== finalstring[len - 1 - i]) {
return false;
}
}
return true;
}
console.log(isPalindrome("madam i'm adam"));
Is there anything wrong with my code? Point to be noted, I'm not allowed to use any built-in or library function. Your help would be much appreciable. Tnx.
Within the "for" clause, replace "Math.floor(finalstring/2)" by "Math.floor(len/2)"
Also, you might want to improve your punctuation removal so that it also removes apostrophes, for instance.
So your code would become the following:
function isPalindrome (str) {
var nopunctuation = str.replace(/\W/g,"");
var nospaces = nopunctuation.replace(/\s/g,"");
var finalstring = nospaces;
var len = finalstring.length;
for ( var i = 0; i < Math.floor(len/2); i++ ) {
if (finalstring[i] !== finalstring[len - 1 - i]) {
return false;
}
}
return true;
}

Test if input values match constant value

Ive got an assignment and am a bit stuck.
Need to match an input string to the values in a constant, but I am matching individual characters.
My constant would be ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUWXYZ'
My input would be, var input = 'ABOZ'
I need a test to check if each letter in the input variable exist in the ALPHABET constant.
Hope I made sense.
Cheers
Here's a single line answer to your question:
(ALPHABET.match(new RegExp((input.split('').join('|')), 'g'))).length == input.length
which would return true only if all the characters in input are present in ALPHABET
Here's a working demo http://jsfiddle.net/kayen/akL4A/
One way is to loop over the input and search if it exits in the constant
Possible code
var ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUWXYZ';
var input = 'ABOZ'
var count = 0;
for(x in input) {
if(ALPHABET.indexOf(input[x])>-1){
count++;
continue;
}
else{
break;
}
}
if(count==input.length) {
alert("true");
}
Demo
Tested and works in Firefox 16. Remember this implementation does not verify if input is null or other defensive checks. You should do it by yourself.
This is a case sensitive result.
Case insensitive :
function validInput(input) {
var ALPHABET = "ABCDEFGHIJKLMNOPQRSTUWXYZ";
for (var i = 0; i < input.length; i++) {
var charAtI = input.charAt(i);
var indexOfCharAtI = ALPHABET.indexOf(charAtI);
if (indexOfCharAtI < 0) {
return false;
}
}
return true;
}
Case insensitive :
function validInput(input) {
var ALPHABET = "ABCDEFGHIJKLMNOPQRSTUWXYZ";
for (var i = 0; i < input.length; i++) {
var charAtI = input.charAt(i);
charAtI = charAtI.toUpperCase();
var indexOfCharAtI = ALPHABET.indexOf(charAtI);
if (indexOfCharAtI < 0) {
return false;
}
}
return true;
}
Here's an example of a function which would return true for a match or false for a mismatch. (Please note this is a case sensitive test).
var ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
var input = 'ABOZ';
function testStr(str, constant){
var matchFlag = true;
var strSplit = str.split("");
for(var i=0; i<strSplit.length;i++){
if(constant.indexOf(strSplit[i]) == -1){
matchFlag = false;
}
}
return matchFlag;
}
alert(testStr(input, ALPHABET)); //TRUE
DEMO

Javascript Function to split and return a value from a string

I am trying to grab a certain value. I am new to javascript and I can't figure out why this is not working.
If I parse "kid_2" I should get "kostas". Instead of "Kostas" I always get "02-23-2000". So I must have a logic problem in the loop but I am really stuck.
function getold_val(fieldname,str){
var chunks=str.split("||");
var allchunks = chunks.length-1;
for(k=0;k<allchunks;k++){
var n=str.indexOf(fieldname);
alert(chunks[k]);
if(n>0){
var chunkd=chunks[k].split("::");
alert(chunkd);
return chunkd[1];
}
}
}
var test = getold_val('kid_2','date_1::02-23-2000||date_2::06-06-1990||kid_1::George||kid_2::Kostas||');
alert(test);
A regex may be a little more appealing. Here's a fiddle:
function getValue(source, key){
return (new RegExp("(^|\\|)" + key + "::([^$\\|]+)", "i").exec(source) || {})[2];
}
getValue("date_1::02-23-2000||date_2::06-06-1990||kid_1::George||kid_2::Kostas||","kid_2");
But if you want something a little more involved, you can parse that string into a dictionary like so (fiddle):
function splitToDictionary(val, fieldDelimiter, valueDelimiter){
var dict = {},
fields = val.split(fieldDelimiter),
kvp;
for (var i = 0; i < fields.length; i++) {
if (fields[i] !== "") {
kvp = fields[i].split(valueDelimiter);
dict[kvp[0]] = kvp[1];
}
}
return dict;
}
var dict = splitToDictionary("date_1::02-23-2000||date_2::06-06-1990||kid_1::George||kid_2::Kostas||","||","::");
console.log(dict["date_1"]);
console.log(dict["date_2"]);
console.log(dict["kid_1"]);
console.log(dict["kid_2"]);​
This works, here's my fiddle.
function getold_val(fieldname,str) {
var chunks = str.split('||');
for(var i = 0; i < chunks.length-1; i++) {
if(chunks[i].indexOf(fieldname) >= 0) {
return(chunks[i].substring(fieldname.length+2));
}
}
}
alert(getold_val('kid_2', 'date_1::02-23-2000||date_2::06-06-1990||kid_1::George||kid_2::Kostas||'));
The issue with your code was (as #slebetman noticed as well) the fact that a string index can be 0 because it starts exactly in the first letter.
The code is almost the same as yours, I just didn't use the second .split('::') because I felt a .substring(...) would be easier.
There are two bugs. The first error is in the indexOf call:
var n = str.indexOf(fieldname);
This will always return a value greater than or equal to 0 since the field exists in the string. What you should be doing is:
var n = chunks[k].indexOf(fieldname);
The second error is in your if statement. It should be:
if(n >= 0) {
...
}
or
if(n > -1) {
...
}
The substring you are looking for could very well be the at the beginning of the string, in which case its index is 0. indexOf returns -1 if it cannot find what you're looking for.
That being said, here's a better way to do what you're trying to do:
function getold_val(fieldName, str) {
var keyValuePairs = str.split("||");
var returnValue = null;
if(/||$/.match(str)) {
keyValuePairs = keyValuePairs.slice(0, keyValuePairs.length - 1);
}
var found = false;
var i = 0;
while(i < keyValuePairs.length && !found) {
var keyValuePair = keyValuePairs[i].split("::");
var key = keyValuePair[0];
var value = keyValuePair[1];
if(fieldName === key) {
returnValue = value;
found = true;
}
i++;
}
return returnValue;
}

Categories

Resources