I've been tasking with creating my own version of the toUpperCase() fucntion in JavaScript. This is what I have come up with. We were given a tester file and denied access to the source code. My output is as follows:
function stringToUppercase(string) {
/*
upper = ['A','B','C', etc...]
compare lowerY to upperY get index numbers of lowercase[y] that matches and use those to
create matching values at upperCase[y]
will print newString based on compared upper and lower values
*/
const upperCase = ["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"];
const lowerCase = ["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"];
const numbers = ['0','1','2','3','4','5','6','7','8','9'];
const specialChar = ['`','~','!','#','#','$','%','^','&','*','(',')','-','_','+','=','{','}','[',']','|',';',':','"','<'];
let newString = "";
for (let x = 0; x < string.length; x++){
for (let y = 0; y < lowerCase.length; y++) {
if (string[x] === lowerCase[y] || string[x] === upperCase[y]) {
newString += upperCase[y];
} else if (string[x] === '\n' || string[x] === '\t' || string[x] === ' '){
newString += string[x];
} else if (string[x] === numbers[y]) {
newString += string[x];
} else if (string[x] === specialChar[y]) {
newString += string[x];
}
}
}
return newString;
}
I have coded it up again, but this time following your requirements:
function stringToUppercase(string) {
const lowerCase = ["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"];
const upperCase = ["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"];
var newString = "";
outer:
for (var char = 0; char < string.length; char ++) {
for (var letter = 0; letter < lowerCase.length; letter ++) {
if (string[char] == lowerCase[letter]) {
newString += upperCase[letter];
continue outer;
}
}
newString += string[char];
}
return newString;
}
I have coded up a much more efficient 'stringToUppercase' function for you:
function stringToUppercase(string) {
const lowerCase = ["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"];
const upperCase = ["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"];
var newString = string;
for (var char = 0; char < lowerCase.length; char += 1) {
for (var x = 0; x < string.split(lowerCase[char]).length; x += 1) {
newString = newString.replace(lowerCase[char], upperCase[char]);
}
}
return newString;
}
Here's probably the most efficient solution.
function stringToUppercase(str) {
let out = "";
for (let i=0; i<str.length; i++) {
let charCode = str.charCodeAt(i);
if (charCode >= 0x61 && charCode <= 0x7A)
out += String.fromCharCode(charCode - 0x20);
else
out += str[i];
}
return out;
}
However, since you can't use built-in functions:
function stringToUppercase(string) {
const caseMap = {"a":"A", "b":"B", "c":"C", "d":"D", "e":"E", "f":"F", "g":"G", "h":"H", "i":"I", "j":"J", "k":"K", "l":"L", "m":"M", "n":"N", "o":"O", "p":"P", "q":"Q", "r":"R", "s":"S", "t":"T", "u":"U", "v":"V", "w":"W", "x":"X", "y":"Y", "z":"Z"}
var newString = "";
for (var i = 0; i < string.length; i += 1) {
const char = string[i];
if (char in caseMap)
newString += caseMap[char];
else
newString += char;
}
return newString;
}
/Write a function called weave that accepts an input string and number. The function should return the string with every xth character replaced with an 'x'./
function weave(word,numSkip) {
let myString = word.split("");
numSkip -= 1;
for(let i = 0; i < myString.length; i++)
{
numSkip += numSkip;
myString[numSkip] = "x";
}
let newString = myString.join();
console.log(newString);
}
weave("weave",2);
I keep getting an infinite loop. I believe the answer I am looking for is "wxaxe".
Here's another solution, incrementing the for loop by the numToSkip parameter.
function weave(word, numToSkip) {
let letters = word.split("");
for (let i=numToSkip - 1; i < letters.length; i = i + numToSkip) {
letters[i] = "x"
}
return letters.join("");
}
Well you need to test each loop to check if it's a skip or not. Something as simple as the following will do:
function weave(word,numSkip) {
var arr = word.split("");
for(var i = 0; i < arr.length; i++)
{
if((i+1) % numSkip == 0) {
arr[i] = "x";
}
}
return arr.join("");
}
Here is a working example
Alternatively, you could use the map function:
function weave(word, numSkip) {
var arr = word.split("");
arr = arr.map(function(letter, index) {
return (index + 1) % numSkip ? letter : 'x';
});
return arr.join("");
}
Here is a working example
Here is a more re-usable function that allows specifying the character used for substitution:
function weave(input, skip, substitute) {
return input.split("").map(function(letter, index) {
return (index + 1) % skip ? letter : substitute;
}).join("");
}
Called like:
var result = weave('weave', 2, 'x');
Here is a working example
You dont need an array, string concatenation will do it, as well as the modulo operator:
function weave(str,x){
var result = "";
for(var i = 0; i < str.length; i++){
result += (i && (i+1)%x === 0)?"x":str[i];
}
return result;
}
With arrays:
const weave = (str,x) => str.split("").map((c,i)=>(i&&!((i+1)%x))?"x":c).join("");
You're getting your word greater in your loop every time, so your loop is infinite.
Try something like this :
for(let k = 1; k <= myString.length; k++)
{
if(k % numSkip == 0){
myString[k-1]='x';
}
}
Looking at what you have, I believe the reason you are getting an error is because the way you update numSkip, it eventually becomes larger than
myString.length. In my code snippet, I make i increment by numSkip which prevents the loop from ever executing when i is greater than myString.length. Please feel free to ask questions, and I will do my best to clarify!
JSFiddle of my solution (view the developer console to see the output.
function weave(word,numSkip) {
let myString = word.split("");
for(let i = numSkip - 1; i < myString.length; i += numSkip)
{
myString[i] = "x";
}
let newString = myString.join();
console.log(newString);
}
weave("weave",2);
Strings are immutable, you need a new string for the result and concat the actual character or the replacement.
function weave(word, numSkip) {
var i, result = '';
for (i = 0; i < word.length; i++) {
result += (i + 1) % numSkip ? word[i] : 'x';
}
return result;
}
console.log(weave("weave", 2));
console.log(weave("abcd efgh ijkl m", 5));
You can do this with fewer lines of code:
function weave(word, numSkip) {
word = word.split("");
for (i = 0; i < word.length; i++) {
word[i] = ((i + 1) % numSkip == 0) ? "x" : word[i];
}
return word.join("");
}
var result = weave("weave", 2);
console.log(result);
Could someone be kind enough to tell me why "almostomla" returns true in my code.
I have searched and have seen there are simpler versions but im so deep into this code now i need to make it work if at all possible.
Please excuse the terrible variable names, i was frustrated.
function palindrome(str) {
str = str.toLowerCase();
str = str.replace(/ /g, '').replace(/\./g, '').replace(/,/g, '');
for (var i = 0; i < str.length / 2; i++) {
for (var j = str.length - 1; j > str.length / 2 - 1; j--) {
var iDntKnow = str.charAt(i);
var iDntKnowEither = str.charAt(j);
if (iDntKnow === iDntKnowEither) {
return true;
} else {
return false;
}
}
}
}
Appreciate all answers.
While I can understand the frustration of wanting to make something work if you have put time into it, there is also something to be said for starting from the drawing board and not driving yourself crazy. The main problem I see with your code is that you have two loops when you only need one. The second loop is actually sabotaging you. I would suggest running a debugger (type "debugger" into your code and run) to see why.
I believe this is what you are trying to accomplish:
var palindrome = function(str) {
// Put any additional string preprocessing here.
for(var i = 0; i < str.length/2; i++) {
var j = str.length-i-1;
if (str[i] != str[j]) {
return false;
}
}
return true;
}
In this way you are comparing each mirrored element in the string to confirm if the string is a palindrome.
Your question seems to be answered by now.
If performance isn't an issue, why not just use this?
function palindrome(str) {
str = str.toLowerCase();
return (str.split().reverse().join() === str)
}
It splits the string into an array, reverses that and joins it back together. The result is compared to the original string.
You can only know if it's NOT a palindrome in each iteration.
Also, why using nested loops?
function palindrome(str) {
str = str.toLowerCase();
str = str.replace(/ /g, '').replace(/\./g, '').replace(/,/g, '');
for (var i = 0; i < str.length / 2; i++) {
if (str.charAt(i) !== str.charAt(str.length - i - 1)) {
return false;
}
}
return true;
}
This works:
function palindrome(string) {
string = string.toLowerCase();
for (var i = 0; i < Math.ceil(str.length/2); i++) {
var character1 = string.charAt(i);
var character2 = string.charAt(string.length-1-i);
if (character1 !== character2) {
return false;
}
}
return true;
}
Here is a version that omits spaces and commas:
var removeLetterFromString = function(string,letterPos){
var returnString = "";
for(var i = 0; i < string.length; i++){
if(i!==letterPos){
returnString=returnString+string.charAt(i);
}
}
return returnString;
};
var palindrome = function(string) {
string = string.toLowerCase();
var stringCheck="";
var recheck = true;
while(recheck){
recheck=false;
for(var i = 0; i < string.length; i ++){
if(string.charAt(i)===" "||string.charAt(i)===","){
string=removeLetterFromString(string,i);
}
}
for(var i = 0; i < string.length; i ++){
if(string.charAt(i)===" "||string.charAt(i)===","){
recheck=true;
}
}
}
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 made a function that counts the occurances of x's and o's in a given string and returns true if they are equal.
function ExOh(str) {
var x_count = 0;
var o_count = 0;
for (var i = 0;i < str.length-1;i++){
if (str[i] === 'x'){
x_count = x_count + 1;
}
else if (str[i] === 'o'){
o_count = o_count + 1;
}
}
console.log(o_count);
console.log(x_count);
if (x_count === o_count){
return true;}
else{
return false;
}
}
// keep this function call here
// to see how to enter arguments in JavaScript scroll down
ExOh(readline());
I added the lines of code
console.log(o_count);
console.log(x_count);
To see if it was counting correctly and I discovered that was the issue. After testing it I realized that this function is not testing the last element in the string. I tried changing the length of the for loop, but I can't think of what else could be wrong.
Any advice?
Thanks mates
JavaScript arrays are 0 index based objects. So, your loop should be like this
for (var i = 0; i < str.length; i++) {
otherwise the last element will be skipped.
Consider that the length of the string is 5. So, i starts from 0 and if you had your original condition
for (var i = 0; i < str.length - 1; i++) {
following are the comparisons happening in the loop
0 < 4
1 < 4
2 < 4
3 < 4
4 < 4 -- Fails
So it breaks out of the loop. But the last element will be at index 4. But when you have the condition like this
for (var i = 0; i < str.length; i++) {
the comparisons go like this
0 < 5
1 < 5
2 < 5
3 < 5
4 < 5
5 < 5 -- Fails
It breaks out of the loop only after comparing all the elements.
So, your actual program can be written like this
function ExOh(str) {
var x_count = 0, o_count = 0;
for (var i = 0; i < str.length; i++) {
if (str[i] === 'x') {
x_count = x_count + 1;
} else if (str[i] === 'o') {
o_count = o_count + 1;
}
}
return x_count === o_count;
}
alternate method to count characters:
var s = 'example';
s.split('').filter(function (i) { return i === 'e'; }).length; // 2
Your for loop is running one too short. Try this instead.
for (var i = 0;i < str.length;i++){
if (str[i] === 'x'){
x_count = x_count + 1;
}
else if (str[i] === 'o'){
o_count = o_count + 1;
}
}
Your problem is in for loop. Try changing to this.
for (var i = 0; i < str.length; i++) {
If you want to avoid using for loops, you can use this much shorter version of ExOh function.
function ExOh(str) {
return str.match(/o/g).length == str.match(/x/g).length
}
Rather than looping over the whole String with for, I'd see if using indexOf achieves a faster result
function countOccurance(haystack, needle) {
var total = 0, pos = -1;
while (-1 !== (pos = haystack.indexOf(needle, pos + 1)))
total += 1;
return total;
}
Then
var x_count = countOccurance(str, 'x'),
o_count = countOccurance(str, 'o');
return x_count === o_count;
EDIT looks like I might have been wrong about it being faster! jsperf
function indexOfMethod(haystack, needle) {
var total = 0, pos = -1;
while (-1 !== (pos = haystack.indexOf(needle, pos + 1)))
total += 1;
return total;
}
function splitMethod(haystack, needle) {
return haystack.split(needle).length - 1;
}
function forMethod(haystack, needle) {
var total = 0, i;
for (i = 0; i < haystack.length; ++i)
if (haystack.charAt(i) === needle)
total += 1;
return total;
}
The forMethod will only work with char needle, whereas the other two should work with any String as needle, if that matters.
Any ideas on the following? I want to input a number into a function and insert dashes "-" between the odd digits. So 4567897 would become "456789-7". What I have so far is to convert the number into a string and then an array, then look for two odd numbers in a row and use the .splice() method to add the dashes where appropriate. It does not work and I figure I may not be on the right track anyway, and that there has to be a simpler solution.
function DashInsert(num) {
var numArr = num.toString().split('');
for (var i = 0; i < numArr.length; i++){
if (numArr[i]%2 != 0){
if (numArr[i+1]%2 != 0) {
numArr.splice(i, 0, "-");
}
}
}
return numArr;
}
The problem is you're changing the thing you're iterating over. If instead you maintain a separate output and input...
function insertDashes(num) {
var inStr = String(num);
var outStr = inStr[0], ii;
for (ii = 1; ii < inStr.length; ii++) {
if (inStr[ii-1] % 2 !== 0 && inStr[ii] % 2 !== 0) {
outStr += '-';
}
outStr += inStr[ii];
}
return outStr;
}
You can try using regular expressions
'4567897'.replace(/([13579])(?=[13579])/g, '$1-')
Regex Explained
So, we find an odd number (([13579]) is a capturing group meaning we can use it as a reference in the replacement $1) ensure that it is followed by another odd number in the non-capturing positive lookahead ((?=[13579])) and replace the matched odd number adding the - prefix
Here is the function to do it:
function dashes(number){
var numString = '';
var numArr = number.toString().split('');
console.log(numArr);
for(i = 0; i < numArr.length; i++){
if(numArr[i] % 2 === 1 && numArr[i+1] % 2 === 1){
numString += numArr[i] + '-';
}else{
numString += numArr[i];
}
}
console.log(numString);
}
dashes(456379);
Tested and everything.
Edit: OrangeDog's answer was posted earlier (by nearly a full half hour), I just wanted to make an answer which uses your code since you're almost there.
Using another array instead of splicing into one you were looping through (this happens to return a string using join):
var num = 4567897;
function DashInsert(num) {
var numArr = num.toString().split('');
var len = numArr.length;
var final = [];
for (var i = 0; i < len; i++){
final.push(numArr[i]);
if (numArr[i]%2 != 0){
if (i+1 < len && numArr[i+1]%2 != 0) {
final.push("-")
}
}
}
return final.join("");
}
alert(DashInsert(num));
function dashInsert(str) {
var arrayNumbers = str.split("");
var newString = "";
for (var i = 0; i < arrayNumbers.length; i++){
if(arrayNumbers[i] % 2 === 1 && arrayNumbers[i + 1] % 2 === 1){
newString = newString + arrayNumbers[i] + "-";
} else {
newString = newString + arrayNumbers[i];
}
}
return newString;
}
var result = dashInsert("3453246");
console.log(result);