Javascript: Broken letter shifting function [closed] - javascript

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 9 years ago.
Improve this question
Trying to write a simple function to take a string as input, then shift each character over once alphabetically. (a -> b) (f -> g) (z -> a). My function so far is broken. I'm sure there are better ways to go about this, but if someone would be willing to troubleshoot my function that would be awesome. :)
function translate(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'];
str.toLowerCase();
var i = 0;
var j;
//edit: deleted str = ""
while (i < str.length) {
for (j = 0; j < alphabet.length; j++) {
if (str[i] == alphabet[alphabet.length - 1]) { //changed data type
str += alphabet[0]
j=0;
} else if (str[i] == alphabet[j]) {
str += alphabet[j+1]; //fixed this
j=0;
} else {
i++;
}
}
}
return str;

You could also use charCodeAt and fromCharCode to realize your shifting. I might be a little bit more convienent:
function translate(str) {
res = [];
for (var i = 0; i < str.length; i++) {
var ch = str.charCodeAt(i);
//65 => A
//90 => Z
//97 => a
//122 => z
//if ch betweet A and Z or between a and z
if ((ch >= 65 && ch <= 90) || (ch >= 97 && ch <= 122)) {
//if z or Z transform to a or A respectively
if (ch === 90 || ch === 122) ch -= 25;
//else increase by one
else ch += 1;
}
res.push(ch);
}
return = String.fromCharCode.apply(this, res);
}
Both methods use unicode representation of the string. Essentially, you transform the single characters into numbers, increase those numbers by one and transform it back to a letter. Here is a unicode table that shows the value of each letter: http://www.utf8-chartable.de/unicode-utf8-table.pl?utf8=dec

Your logic is a little flawed. Just iterate through the string and use the indexOf method along with the modulo operator:
var index = alphabet.indexOf(char.toLowerCase());
if (index === -1) {
// char isn't in the alphabet, so you should skip it
} else {
var newChar = alphabet[(index + 1) % alphabet.length];
}
(index + 1) adds 1 to the index, which selects the next letter, and % alphabet.length makes it wrap around to the beginning in case of z.

Here's one way to do it:
function translate(str) {
var newStr = "";
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'];
for (var i = 0; i < str.length; i++) {
var currentLetter = str.substring(i, i+1);
var newLetter = alphabet[(alphabet.indexOf(currentLetter.toLowerCase()) + 1) % alphabet.length];
// preserve the case of the letter
newStr += (currentLetter === currentLetter.toUpperCase()) ? newLetter.toUpperCase() : newLetter;
}
return newStr;
}
The general idea is to loop through each character, find its position in the alphabet array, and add its successor to the new string.
You'll have to add more logic if you need it to handle strings containing symbols, numbers, etc.

I can see a few problems here.
var str = "";. str is the variable you are sending as a parameter, so you reset it with this statement.
if (str[i] == alphabet.length - 1). str[i] and alphabet.length - 1 are not the same data type, so this statement is probably not doing what you think it should. Maybe you should have alphabet[alphabet.length - 1] instead.
else if (str[i] == alphabet[j]) { str += alphabet[j]; //... }. This would add the same letter onto your result string if you didn't reset str like in #1. You should have something like alphabet[(j+1) % alphabet.size] instead.
Also, you should use charAt(i) for getting characters in a string, not subscripts ([]), and you don't have to call j=0 at the end of your for loops, since you already say j=0 in the loop.

Related

Browser crashing while loop JavaScript algorithm

Guys i'm trying to write an algorithm where I pass in a large string and let it loop through the string and whatever palindrome it finds, it pushes into array but for some reason my browser is crashing once i put in the while loop and I have no
function arrOfPalindromes(str) {
var palindromeArrays = []
var plength = palindromeArrays.length
// grab first character
// put that in a temp
// continue and look for match
// when match found go up one from temp and down one from index of loop
// if matched continue
// else escape and carry on
// if palendrome push into array
var counter = 0;
for (var i = 0; i < str.length; i++) {
for (var j = 1; j < str.length - 1; j++) {
if (str[i + counter] === str[j - counter]) {
while (str[i + counter] === str[j - counter]) {
console.log(str[j], str[i])
// append the letter to the last index of the array
palindromeArrays[plength] += str[i]
counter++
}
}
}
}
return palindromeArrays
}
var result2 = arrOfPalindromes('asdfmadamasdfbigccbigsdf')
console.log(result2)
Do not mention about the algorithm but the condition
while (str[i + counter] === str[j - counter])
Make your code crash. A little surprise but str[j+counter] when j+counter > str.length return undefined and the same as j-counter <0. There for, your while loop never end because of undefined === undefined.
Returning same sized array to handle nested palis.
ex: abxyxZxyxab => 00030703000 odd numbered nested palis.
ex: asddsa => 003000 even numbered pali.
ex: asdttqwe => 00020000 i dont know if this is a pali but here we go
smallest pali is 2 char wide so i start at index:1 and increment till str.len-1
for (var i = 1; i < str.length-1; i++) {
counter=0;
while(str[i]+1-counter == str[i]+counter || str[i]-counter == str[i]+counter) { // always true when counter is 0
// while (even numbered palis || odd numbered palis)
// IF counter is bigger than 0 but we are still here we have found a pali & middle of the pali is i(or i+0.5) &size of the pali is counter*2(or+1)
if(str[i]+1-counter == str[i]+counter){//even sized pali
res[i]=counter*2;
}else{//odd sized pali
res[i]=counter*2+1;
}
counter++;//see if its a bigger pali.
}
}
not super optimized while + if,else checks same stuff. These can be somehow merged. Maybe even even and odd can be handled without any checks.
You don't need to use three loops. You can do it with two for loops where one starts from the beginning and other one is from the end of the string.
Here we use array reverse() method to match palindromes.
Also I added additional minLength parameter and duplication removal logic to make it more nice.
function findPalindromes(str, minLength) {
var palindromes = [];
var _strLength = str.length;
for (var i = 0; i < _strLength; i++) {
for (var j = _strLength - 1; j >= 0; j--) {
if (str[i] == str[j]) {
var word = str.substring(i, j + 1);
//Check if the word is a palindrome
if (word === word.split("").reverse().join("")) {
//Add minimum length validation and remove duplicates
if(word.length >= minLength && palindromes.indexOf(word) === -1){
palindromes.push(word);
}
}
}
}
}
return palindromes;
}
var result = findPalindromes('asdfmadamasdfbigccbigsdf', 2)
console.log(result)

I am trying to loop through an array of all the alphabets and capitalize every other alphabet. any solutions?

this is the code i came up with:
var alpha = "abcdefghijklmnopqrstuvwxyz".split('');
// console.log(alpha);
// console.log(alpha.length);
for(i=0; i < alpha.length + 1; i++){
if (alpha.indexOf('a', +1) % 2 === 0){
console.log(indexOf('a'));
} else {
console.log("didn't work");
}
};
A simple loop with a step:
for (var i = 0; i < alpha.length; i+=2) {
alpha[i] = alpha[i].toUpperCase();
}
alpha.join(''); // AbCdEfGhIjKlMnOpQrStUvWxYz
If aBcDeFgHiJkLmNoPqRsTuVwXyZ is what you want to achieve, than you can do something like this:
var alpha = 'abcdefghijklmnopqrstuvwxyz';
var result = '';
for (var i = 0; i < alpha.length; i++) {
if ((i + 1) % 2 === 0){
result += alpha[i].toUpperCase();
} else {
result += alpha[i];
}
}
console.log(result);
You can map your array and upper case every second character:
var alpha = "abcdefghijklmnopqrstuvwxyz".split('').map(function(ch, i) {
return i % 2 ? ch.toUpperCase() : ch;
});
console.log(alpha);
The issue with strings is that you can't edit them, once created they stay the same. Most actions on them create a new string.
To avoid doing this lots of times, we do the following
var alpha = 'abcdefghijklmnopqrstuvwxyz'.split('');
Convert the string into an an array
for (var i = 0; i< alpha.length; i++) {
if(i % 2 == 0) {
go down the array, and for every other entry (i % 2 gives us 0 every other time).
alpha[i] = alpha[i].toUpperCase();
convert it to upper case
}
}
var newString = alpha.join('');
and finally make a new string by joining all the array elements together. We have to provide a null string ie '' because if we didn't provide anything we would join with commas (,)
var alpha = "abcdefghijklmnopqrstuvwxyz".split('');
for(i=0; i < alpha.length; i++){
console.log(alpha[i].toUpperCase());
//If you want to update
alpha[i] = alpha[i].toUpperCase();
};

function is returning numbers instead of letters

I am trying to make a function that will return the last letter of each word in a string, and think I am close, but whenever I invoke the function, I get a series of numbers instead of the letters I am looking for.
This is the code:
function lastLetter(str){
var arr = [];
for(var i = 0; i < str.length; i++){
if(str[i] === " " || str[i] === "."){
arr.push((i) - 1);
}
}
return arr;
}
lastLetter("I love bacon and eggs.");
Any advice would be appreciated. Thanks!!
You push the value i - 1 onto the array. You meant to push str.charAt(i-1):
arr.push(str.charAt(i - 1));
See: String charAt().
Note that your code isn't really defensive. If there is a space or period at the first character in the string, you are referencing the character at position -1, which is not valid. You could solve this by looping from 1 instead of 0. In that case you would still get a space in the result if the string starts with two spaces, but at least you won't get an error. A slightly better version of the algorithm would test if i-1 is a valid index, and if there is a character at that position that is not a space or a period.
Below is a possible solution, which I think solves those cases, while still retaining the structure of the code as you set it up.
function lastLetter(str){
var arr = [];
for(var i = 1; i < str.length; i++){
var p = str.charAt(i-1);
var c = str.charAt(i);
if ( (c === " " || c === ".") &&
!(p === " " || p === ".") ) {
arr.push(p);
}
}
return arr;
}
console.log(lastLetter("... Do you love bacon and eggs..."));
Try:
arr.push(str[i - 1]);
This will have problems with multi-byte characters, however.
You're pushing the integer value i-1 rather than the character str[i-1].
You are pushing the index into your array. You still need to access i-1 of your string
`
` function lastLetter(str){
var arr = [];
for(var i = 0; i < str.length; i++){
if(str[i] === " " || str[i] === "."){
arr.push(str[(i) - 1]);
}
}
return arr;
}
lastLetter("I love bacon and eggs.");
Solution and Improved version below:
use arr.push(str.charAt(i - 1)) instead of arr.push((i) - 1)
(You where saving the position of the last letter, but not it's value - charAt(position) does give you the latter at the given position
charAt(): http://www.w3schools.com/jsref/jsref_charat.asp
Demo:
function lastLetter(str){
var arr = [];
for(var i = 0; i < str.length; i++){
if(str[i] === " " || str[i] === "."){
arr.push(str.charAt(i - 1));
}
}
return arr;
}
document.body.innerHTML = lastLetter("I love bacon and eggs.");
Improved Version:
function lastLetter(str) {
var arr = [];
var words = str.split(/[\s\.?!:]+/)
for (var i = 0; i < words.length; ++i) {
if (words[i].length > 0) {
var lastLetter = words[i].charAt(words[i].length - 1)
arr.push(lastLetter);
}
}
return arr;
}
document.body.innerHTML = lastLetter("... Is this: correct?! I love bacon and eggs.");

Eloquent Javascript: Chessboard

Write a program that creates a string that represents an 8×8 grid, using newline characters to separate lines. At each position of the grid there is either a space or a “#” character. The characters should form a chess board.
My code keeps creating an 8 x 8 structure with all hashes.
Can someone offer some advice to edit my code?
var size = 8;
var str = "";
var altern = false;
var line = 1;
while (line <= size) {
var character = 1;
while (character <= size) {
if (altern) {
if (character % 2 === 0) {
str += "#";
console.log(character);
console.log(str);
} else {
str += " ";
console.log(character);
console.log(str);
}
} else {
if (character % 2 === 0) {
str += " ";
console.log(character);
console.log(str);
} else {
str += "#";
console.log(character);
console.log(str);
}
}
altern = !altern;
character++;
}
str += "\n";
line++;
}
console.log(str);
By using both altern and character % 2 you select the branch with the # every iteration. Use only one of the two.
I couldn't figure out how to answer this myself until I found OP's code. Here is what I found would work:
var size = prompt("What is the size?");
var str = "";
var line = 0;
//Instead of using 1, use 0. It'll make sense in the next comment.
while (line < size) {
var character = 0; // Changed this to 0 as well.
while (character < size) {
if (line % 2 === 0){
/*Instead of using logic negate(altern = !altern), you could use one of the variables
you already have. Changing line = 1 to line = 0, we now can write the conditon above.
Where the first line holds true, because 0 % 2 === 0 is true.*/
if (character % 2 === 0) {
str += " "; // I switched the string values around, to get what is resembled in the book.
console.log(character);
console.log(str);
} else {
str += "#"; // Here
console.log(character);
console.log(str);
}
} else {
if (character % 2 === 0) {
str += "#"; // Here
console.log(character);
console.log(str);
} else {
str += " "; // Here
console.log(character);
console.log(str);
}
}
character++;
}
str += "\n";
line++;
}
alert(str);
//Changed this so the final result is easier to see, rather than in the jumbled mess of the console.
I suspect that you want to toggle altern with each new line, not with each square.
You have a loop inside a loop here. Move your altern toggle code from the inner loop to the outer loop.
while (line <= size) {
var character = 1;
while (character <= size) {
// inner loop code here
character++;
}
// Outer loop end code. HERE is where you toggle altern
str += "\n";
line++;
altern = !altern;
}
Below one works but I replaced spaces with Os (capital o's) and a little change in your code.
var size = 8;
var str = "";
var altern = false;
var line = 1;
while (line <= size) {
var character = 1;
while (character <= size) {
console.log('altern: ' + altern + 'character: ' + character);
if (altern) {
if (character % 2 === 0) {
str += "O";
console.log(character);
console.log(str);
} else {
str += "#";
console.log(character);
console.log(str);
}
} else {
if (character % 2 === 0) {
str += "O";
console.log(character);
console.log(str);
} else {
str += "#";
console.log(character);
console.log(str);
}
}
altern = !altern;
character++;
}
str += "\n";
line++;
}
// console.log(str);
alert(str);
This one works, but not, I suggest you to try to re-write this code in a better way. Hint: pay attention to what #koenpeters said.
Instead of using all those loops you could do this:
var width = 8,
height = 8,
str = new Array(1 + (width * height + height) / 2).join('# ').replace(new RegExp('(.{' + width + '}).', 'g'), '$1\n');
Works as long as width isn't even while at the same time height is odd.
If you just need it for this one specific case you could also get rid of a bit of the overhead and just use this:
var str = new Array(37).join('# ').replace(/(.{8})./g, '$1\n')
Instead of a while loop and over-repetition of your cases based on location (i.e. even vs odd) use two for loops and one case statement for whether a location needs a # vs " ". Store them to a var, then print the var once it is complete.
var board = "";
var countX = 0;
var countY = 0;
var size = 8;
for(var i = 0; i < size; i++) {
for(var j = 0; j < size; j++) {
if((countX + countY) % 2 == 0) {
board += " ";
}
else {
board += "#";
}
countX++;
}
board += "\n";
countY++;
}
console.log(board);
board output:
# # # #
# # # #
# # # #
# # # #
# # # #
# # # #
# # # #
# # # #
i would have tackle this problem by first using a while loop to printing out a line of 8 harsh (########) symbol , then repeat it 8 times vertically using another loop, write a test condition that changes the value of y when the value of both iteration are even numbers.
const size = 8
for(let i = 0; i < size; i++){
let y = " "
let cols = 0;
if(i % 2 == 0){
y = "";
}else{
y = " ";
}
while(cols < size){
if( cols % 2 == 0){
y = y + "#"}
else{
y = y + " "
}
rows++
}
console.log(y)
}
Nested For Loop will work the best for this solution as below ---
//to get the input from the user for any size of the array
var charSize=prompt('Enter Number');
var boardChar = "";
//outer loop
for (let i = 1; i <= charSize; i++) {
//inner loop
for (let j = 1; j <= charSize; j++) {
//Check for even column
let evenCol = (i + j) % 2;
if (evenCol == 0) {
boardChar += " ";
} else {
boardChar += "#";
}
}
boardChar += "\n";
}
console.log(boardChar);
//OUTPUT
[Output Image][1]
The essential thing to realise is that given the N th row, its first square will be black if N is odd, and white otherwise.
Also, if the first square of a given row is black, then for a given column M, the square will be black if M is odd, and white if M is even.
Similarly, if the first square is white, then for a column M, the square will be white if M is odd, and black otherwise.
Hope that helps.
EDIT:
try this if you’re a fan of unreadable code:
for i in range(8):
s = ''
for j in range(8):
if (i - j%2) % 2 == 0:
s = s + "#"
else: s = s + 'O'
print s
I also learn JavaScript currently. I was stuck on that for one day. The only thing, that I realize, that if you want to do something useful in JavaScript use loops.
I don't have an idea about complicated coding, but loops could easily do things, that seems at first to be complicated.
Here is my version:
let b = "" //**just create an empty string, because if you won't do that, loop will print out symbols, numbers etc in a single column, but if you use empty string you can in future write symbols inside that string, which allows you to expand string horisontally
let size = 8 //**since loops start at 0 to infinity, you must take it into account,
for (let i = 0; i < size; i++) //**create first loop --> (; ; ). As you can see inside body of loop (the expression, that will be executed until loop is valid) I have just b = b + "#", which means, that my first "for" loop will do looping :) 8 times and will store inside "b" variable THE LAST VALUE (it will be ########), you can check this out in a single sheet (and you will see, that this looping is still going vertically, but the point is that it stores the LAST VALUE)
{ b = b + "#"} //**that is the body of first loop which is described clearly above
for (let a = 0; a < size; a++) //**inside second loop, we create the same routine, and proceed inside that loop with value of "b" from first loop. Notice, that first loop is enclosed {}, so it act independantly.
{
if (a % 2 == 0) //**just condition, which allows us to distribute different strings (rows) of code (I hope you understand what is inside parenthesis
{console.log (" " + b)} //**Since we want to see our chessboard we should print this out onto screen, for that we use "console.log" but again, notice, that here WE DON'T change value of variable "b", we just operate with it, but it will stay the same "########"
else{
console.log (b)} //** And if "if" fails, we will proceed with "########" value, which is NEW origin of "b" variable
}

Javascript procedure to decompress a string of decimal digits

I just started learning JavaScript and I'm extremely annoyed by it.
I want a procedure that decompresses a string of decimal digits like so:
"301051" means "3 zeros, a one, a zero, then 5 ones"
i.e.
"301051"---> "0001011111"
A string of digits of ones and zeros won't be changed at all (and also won't have any more than two consecutive 0's or 1's)
"01001100" ---> "01001100"
I started to work on it, but I'm churning out spaghetti code.
for (i = 0; i < thisString.length;)
{
thisNum = thisString.charCodeAt(i);
if (thisNum > 1)
{
substr = "";
for (j = 0; j < thisNum; j++)
subtr += thisString.charAt(i);
if (i == 0)
thisString = substr + thisString.substring(2
}
}
I don't feel like finishing that because I'm sick of using the limited number of JavaScript string functions. I'm sure the geniuses at Stack Overflow have a 1-line solution for me. Right, guys????
Here's a simple algorithmic solution:
function decompress(str) {
var result = "", char = "";
for (var i = 0; i < str.length; i++) {
char = str.charAt(i);
console.log(char - '0');
if (char > 1) {
result += new Array(+char + 1).join(str.charAt(++i));
} else {
result += char;
}
}
return result;
}
And an even simpler regex solution:
function decompress(str) {
return str.replace(/([2-9])(.)/g, function(m, a, b) {
return new Array(+a + 1).join(b);
});
}
The only magic here is the new Array(+a + 1).join(b) (which is also used by both solutions). The first + turns a (or char) into a number. Then I create an array of a + 1 elements, and join them together with following character as 'glue'. The result is a string of a repetitions of b.
I believe you need something like:
function decompress(thisString) {
var result = '';
for (var i = 0; i < thisString.length; i += 2) {
var thisNum = parseInt(thisString[i], 10);
if (thisNum > 1) {
for (var j = 0; j < thisNum; j++)
result += thisString[i + 1];
} else {
result += (thisString[i] + thisString[i + 1]);
}
}
return result;
}
You have a lot of variables, which are leaking as globals. Make sure you declare each of them using var.

Categories