I am trying to replace all the letters of a string by the next letter in the alphabet.
For example: a --> b or i --> j.
My program is ignoring the if statement that checks a letter against the alphabet array. When I try running the code it replaces all letters by "A", the last element in the alphabet array.
Although inefficent, I cannot find any errors with this algorithm. So why is the program ignoring the if statement?
function LetterChanges(str){
var alphabet = ["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","a"];
str = str.toLowerCase();
var ans = str.split("");
for(i = 0; i < ans.length; i ++)//Running through for each letter of the input string
{
for(a = 0; a < 26; a++)//Checking each letter against the alphabet array
{
if(alphabet[a] == ans[i])
{
ans[i] = alphabet[a+1];
}
}
}
return ans;
}
LetterChanges("Argument goes here");
The reason why it is not working, is because the ans array is modified, whilst you are still checking it.
In this loop:
for(a = 0; a < 26; a++)//Checking each letter against the alphabet array
{
if(alphabet[a] == ans[i])
{
ans[i] = alphabet[a+1];
}
}
If the if statement is found to be true, ans[i] will be updated, but then on the next loop of the iteration, it will likely be true again, as you are checking against the updated ans[i] variable.
As #xianshenglu suggested, you can fix this issue by adding a break to escape from the inner loop once a correct match is found.
for(a = 0; a < 26; a++) {
if(alphabet[a] == ans[i]) {
ans[i] = alphabet[a+1]
// escape from the inner loop once a match has been found
break
}
}
For an alternative way to do this, you could do the following:
var result = str.toLowerCase().split('').map(ch => {
var pos = alphabet.indexOf(ch)
return pos >= 0 ? alphabet[pos + 1] : ch
}).join('')
And if you want to get rid of the alphabet array, you can use char codes. For example:
var result = str.toLowerCase().split('').map(ch => {
var code = ch.charCodeAt(0)
if(code < 96 || code > 122){ return ch }
return String.fromCharCode((code - 96) % 26 + 97)
}).join('')
you lost break when if executed
function LetterChanges(str){
var alphabet = ["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","a"];
str = str.toLowerCase();
var ans = str.split("");
for(i = 0; i < ans.length; i ++)//Running through for each letter of the input string
{
for(a = 0; a < 26; a++)//Checking each letter against the alphabet array
{
if(alphabet[a] == ans[i])
{
ans[i] = alphabet[a+1];
break;
}
}
}
return ans;
}
console.log(LetterChanges("Argument goes here"));
Related
I want to write a function that accepts str1 and str2 and checks if str1 digits can be rearranged into str2.
Currently stuck at this:
My code works fine until str2 won't have any double digits.
How can I fix this?
function scramble(str1, str2) {
str1 = str1.split('');
str2 = str2.split('');
let result = [];
for (let i = 0; i < str2.length; i++) {
for (let j = 0; j < str1.length; j++) {
if (str2[i] === str1[j]) {
result.push(str1[j]);
}
}
}
for (let i = 0; i < result.length; i++) {
if (result[i] === result[i + 1]) {
result.splice(i, 1);
--i;
}
}
return result.join('') === str2.join('')
}
console.log(scramble('rkqodlw','world'));
console.log(scramble('aabbcamaomsccdd','commas')); //heres the problem
You want a count of the various characters in each and use that as comparison.
Following uses Map objects then iterates the str2 counts to make sure the test string (str1) contains equal or greater count for each character in str2
// helper function to map character counts
const charCount = (str) =>{
return [...str].reduce((a,c)=> a.set(c, (a.get(c)||0)+1), new Map)
}
function scramble(str1, str2) {
const s2Counts = charCount(str2),
s1Counts = charCount(str1);
return [...s2Counts.entries()].every(([char,count]) => s1Counts.get(char) >= count)
}
console.log(scramble('rkqodlw','world')); // expect true
console.log(scramble('aabbcamaomsccdd','commas')); // expect true
console.log(scramble('fobar','foobar')); // expect false
A simple method is to check, whether all characters from the second string are contained in the the first one. To deal with double characters in the second string, remove each found character from the first string.
This of course only returns the correct result if the extra characters in the first string don't matter ...
function checkstrings(string1, string2) {
let s1 = [...string1] //convert string1 and
, s2 = [...string2]; //string2 into arrays of char
for (let c of s2) {
let i = s1.indexOf(c); //check if c from s2 is contained in s1
if (i == -1) //if not found result can' be true
return false;
s1.splice(i, 1); //remove c from s1
}
return true;
}
console.log(checkstrings("rkqodlw", "world"));
console.log(checkstrings("aabbcamaomsccdd", "commas"));
console.log(checkstrings("aabbcamaomsccdd", "commmas"));
I am trying to solve a palindrome using a for loop in JavaScript (my code is below).
I cannot figure out what I am doing wrong. If someone can please correct and explain, it will be much appreciated. I am fairly new to coding.
var word = window.prompt("Enter a word");
function palindrome(a) {
var reversed = '';
for (i = 0; i <= a.length; i++) {
reversed = reversed + a[a.length - 1 - i];
}
if (a == reversed) {
return "true";
} else {
return "false";
}
}
document.write(palindrome(word));
On for loop inside palindrome, you have looped from 0 ~ a.length and the item on length index in a string is undefined so reversed will always be undefined.
You need to loop from 0 ~ a.length - 1 as follows.
var word = window.prompt("Enter a word");
function palindrome(a) {
var reversed = '';
for (i = 0; i < a.length; i++) {
reversed = reversed + a[a.length - 1 - i];
}
console.log(reversed);
if (a == reversed) {
return "true";
} else {
return "false";
}
}
document.write(palindrome(word));
You can reverse string simply as follows.
var word = window.prompt("Enter a word");
function palindrome(a) {
const reversed = a.split('').reverse().join('');
if (a == reversed) {
return "true";
} else {
return "false";
}
}
document.write(palindrome(word));
your loop:
for (i = 0; i <= a.length; i++) {
reversed = reversed + a[a.length - 1 - i];
}
you just need remove -1 and start the loop with 1 because when you reached the end of the iteration you will have the length of the word -1 and this will try to access a negative position.
after changing:
for (let i = 1; i <= a.length; i++) {
// you can use reversed += a[a.length - i] instead of;
reversed = reversed + a[a.length - i];
}
You can also reverse a string using the reverse method like this:
reversed = a.split('').reverse().join('');
Finally if you want to validata sentences you need to remove blank spaces and convert it in lower or upper case(usually converted in lowercase) because compare is case sensitive ("Party trap" != "part ytraP").
This code compares the first character to the last character, then advances to compare the second character to the next to last character until it runs out of characters.
As soon as it finds an inequality, it returns false because there is no reason to continue comparing.
let word = window.prompt("Enter a word");
const palindrome = a => {
let last = a.length - 1;
// loop, comparing the values until you find something that doesn't match
for (let first = 0; first <= last; first++, last--) {
if (a[first] !== a[last]) {
return "false";
}
}
// everything matched
return "true";
}
document.getElementById("output").textContent = palindrome(word);
<output id="output"></output>
I'm trying to solve the problem of: Given an array of strings with only lower case letters, make a function that returns an array of those same strings, but each string has its letters rearranged such that it becomes a palindrome (if not possible then return -1). I'm a bit stuck on how I should be rearranging the letters.
let arr = ["hello", "racecra"];
I created a function to first check if a word is a palindrome :
function isPalindrome(arr) {
let obj = {};
for (var x = 0; x < str.length; x++) {
if (obj[arr[x]]) {
obj[arr[x]] += 1;
} else {
obj[arr[x]] = 1;
}
}
let countOdd = 0;
let countEven = 0;
for (let x of Object.values(obj)) {
if (x % 2 == 0) {
countEven += 1;
} else {
countOdd += 1;
}
}
return countOdd == 1 ? true : false
}
then I plan to loop through the words
let emptyArr = [];
for (var x = 0; x < arr.length; x++) {
if (isPalindrome(arr[x]) {
// not sure what to do here. I know the word is a palindrome but not sure how to sort the order of the word in the palindrome form.
} else {
emptyArr.push(-1);
}
}
return emptyArr;
Look closely: you don't need your words to be palindromes, you need them to be rearrangeable as palindromes ("palindrome-candidates"). Now, a word is a palindrome-candidate if all of its letters but one can be counted by an even number (2, 4, 6 etc.)
For example, this...
hollo
... is NOT a palindrome, but can become one, as there's 2 'o', 2 'l' and just one 'h' in it. To rearrange, you just move 'h' in the middle, then just place 'o' and 'l' before and after it:
l -> o -> h <- o <- l
So start with splitting each of your words by characters, then either count those characters or just sort them (as #Barmar suggested). If they satisfy the condition, rearrange the letters following the approach given; if not, return null (or any other special value clearly distinguishable from the rest) immediately.
Here's one way to do it:
function rearrangeAsPalindrome(word) {
if (word.length === 1) return word; // easy win first
const charCounter = word.split('').reduce((counter, ch) => ({
...counter,
[ch]: (counter[ch] || 0) + 1
}), {});
const parts = ['', '', '']; // left, middle, right
const entries = Object.entries(charCounter);
for (let i = 0; i < entries.length; ++i) {
const [char, counter] = entries[i];
if (counter % 2) { // odd
if (parts[1] !== '') return null;
// one odd is already here, eject! eject!
parts[1] = char.repeat(counter);
}
else { // even
const half = counter / 2;
parts[0] = char.repeat(half) + parts[0];
parts[2] += char.repeat(half);
}
}
return parts.join('');
}
console.log(rearrangeAsPalindrome('racarrrac')); // crraaarrc
console.log(rearrangeAsPalindrome('aabbcc')); // cbaabc
console.log(rearrangeAsPalindrome('hollo')); // lohol
console.log(rearrangeAsPalindrome('hello')); // null
This function returns null (and does it early) when it realizes the word given cannot be rearranged as a palindrome - or an actual palindrome if it is possible.
This can help
"How to generate distinct palindromes from a string in JavaScript"
https://medium.com/#bibinjaimon/how-to-generate-distinct-palindromes-from-a-string-in-javascript-6763940f5138
console.log("HİNDİ".toLocaleLowerCase() == "hindi");
console.log("HİNDİ" == "hindi");
console.log("HİNDİ".toLowerCase());
console.log("HİNDİ".toLocaleLowerCase())
console.log("HİNDİ".toLowerCase())
I am building a search functionality but i come across a thing:
"HİNDİ".toLocaleLowerCase() // "hindi"
"hindi" == "HİNDİ".toLocaleLowerCase() //false
What the heck is going on here?
Solution:
#pmrotule's answer seems to work:
function to_lower(s)
{
var n = "";
for (var i = 0; i < s.length; i++) // do it for one character at a time
{
var c = s[i].toLowerCase();
// call replace() only if the character has a length > 1
// after toLowerCase()
n += c.length > 1 ? c[0].replace(/[^ -~]/g,'') : c;
}
return n;
}
Thanks,
It is a problem of string format. toLocaleLowerCase is meant for human-readable display only. However, there is still a trick you can do:
if ("hindi" == "HİNDİ".toLowerCase().replace(/[^ -~]/g,''))
{
alert("It works!");
}
EDIT
If you want to make it works with all special characters:
function to_lower(s)
{
var n = "";
for (var i = 0; i < s.length; i++) // do it for one character at a time
{
var c = s[i].toLowerCase();
// call replace() only if the character has a length > 1
// after toLowerCase()
n += c.length > 1 ? c.replace(/[^ -~]/g,'') : c;
}
return n;
}
console.log("gök" == to_lower("GÖK"));
console.log("hindi" == to_lower("HİNDİ"));
function to_low(s) // shorter version
{
var n = "";
for (var i = 0; i < s.length; i++)
{ n += s[i].toLowerCase()[0]; }
return n;
}
console.log("hindi" == to_low("HİNDİ"));
The problem is that your character İ is composed by 2 characters.
You have the I and then the 'dot' at the top (UTF-8 decimal code: 775).
Try this:
"HİNDİ".toLocaleLowerCase().split('').map((_,v)=>console.log(_.charCodeAt(0)))
Compare it with this:
"hindi".toLocaleLowerCase().split('').map((_,v)=>console.log(_.charCodeAt(0)))
Can anyone help me out with the bug? This is a letter count challenge that you need to return the first word with greatest number of repeated letters, e.g.: Input = "Hello apple pie" Output = Hello
I tried many different ways to debug my code and notice that the string didn't pass into the while loop, but I have no ideas why. Can anyone explain?
function LetterCount(str) {
str = str.split(" ");
var index = 0;
while(index >= str.length){
for(var i = 0; i < str.length; i++){
var str1 = str[i].split("").sort();
for(var k = 0; k < str1.length; k++){
if(index === 0 && str1[k] === str[k+1]){
return str[i];
}
else if(index > 0 && str1[k] === str[k+1]){
return str[i];
}
}
}
index++;
}
return -1;
}
Here's some regex magic to pull it off as well. ;)
function LetterCount(str) {
var parts = str.replace(/(\s+)|([A-Z]*?)([A-Z])(\3+)([A-Z]*)|([A-Z]+)/gi, "$1$2$3$4$5$6,$3$4,").split(',');
var firstIndexOfMaxLetters, maxCount = 0;
for (var i = 1; i < parts.length; i += 2)
if (parts[i].length > maxCount)
{ maxCount = parts[i].length; firstIndexOfMaxLetters = i; }
return firstIndexOfMaxLetters ? parts[firstIndexOfMaxLetters-1] : "";
}
LetterCount("Hi apPple pie")
Output: "apPple"
The regex turns the string into this:
["Hi", "", " ", "", "apPple", "pPp", " ", "", "pie", ""]
... where every second item in the array is the repeating letters (if any, or blank otherwise), and the word is before it. ;)
Taking a quick look as Ewald said your index is 0 so while loop won't be execute. I think will be easier if you store letters on a dictionary.
var niceDict = {};
//save letter and set initial value to zero
var letter = 'e';
niceDict[letter] = 0; // or niceDict['e'] = 0;
//incremente value
niceDict[letter]++;