Replacing alternative letters in a string to either "!" or "?" - javascript

This
I'm able to return T!d!y. But i need T!d?y. I'm new to JS and I cant figure it out =(
function change(str) {
newString = str.split("");
for (let i = 1; i < newString.length - 1; i+=2) {
newString[i] = "!";
//newString[i] = "?";
}
return(newString.join("")); }
console.log(change("Teddy")); should return T!d?y

Use modulo to check whether the i being iterated over is one of the 3-7-11 sequence or the 1-5-9 sequence - then you can determine which character to insert.
function change(str) {
const arr = str.split("");
for (let i = 1; i < arr.length - 1; i += 2) {
arr[i] = i - 1 % 4 === 0
? "!"
: "?";
}
return arr.join("");
}
console.log(change("Teddy"));
Also remember
Declare your variables - doing newString = without a const (or something) before it implicitly creates a global variable, which is very often not what you want
.split returns an array; newString is not an accurate description of what the variable contains (perhaps instead call it arr or newArray or characters, or something like that)

You can add a check and update variable to be replaced.
Few pointers:
When looping, you will have to loop till last character. i < arr.length - 1 will cause issues for certain scenarios.
function change(str) {
const possibilities = [ "!", "?", "*" ];
let index = 0;
let newString = str.split("");
for (let i = 1; i < newString.length ; i += 2) {
newString[i] = possibilities[index % possibilities.length];
index++
}
return (newString.join(""));
}
console.log(change("Teddy"));
console.log(change("Javascript"));

Related

Implement the .split method

I need to implement the .split method in my own way without using prebuilt functions. The method should receive a string divided into 2 sentences by a dot and divide them through a separator.
For example, there is this string:
'word wooord wooooooooord wooooooord. wooooooooord woooooord woooord wooooooooord', separator in this case: '. '
The result should be:
['word wooord wooooooooord wooooooord", "wooooooooord woooooord woooord wooooooooord']
I tried to implement it myself, the first problem I encountered is that the words from the string are added character by character to the new array. The second problem is that the output is still a string even though I declared an array earlier.
function split(str, splitter){
let arrSent = []
for (let i = 0; i < str.length; i++){
if (str[i] != splitter){
arrSent += str[i]
}
}
return arrSent
}
console.log(split('word wooord wooooooooord wooooooord. wooooooooord woooooord woooord wooooooooord', '. '))
Since the delimiter can have more than one character, you need a system to upfront collect a sample of characters (of the same length as the delimiter) to be then compared with the delimiter:
const split = (str, delimiter) => {
// If delimiter is empty string just return an array of characters
if (delimiter === "") return [...str];
const len = delimiter.length;
const iter = str.length - len + 1; // max needed iterations
const arr = [""]; // Prefill it with empty string
let idx = 0; // arr insertion pointer
for (let i = 0; i < iter; i++) {
// Collect len chars from str as a sample
// to compare with the delimiter:
let sample = "";
for (let x = i; x < i + len; x++) {
sample += str[x];
}
const isSplit = sample === delimiter;
const isEnded = i === iter - 1;
if (isSplit) {
i += len - 1; // Consume splitted characters
idx += 1; // Increment arr pointer
arr[idx] = ""; // Prepare the new array key as empty string
} else {
// If loop ended append the entire sample.
// Otherwise, append a single character:
arr[idx] += isEnded ? sample : str[i];
}
}
return arr
}
console.log(split("word. etc", ". "));
console.log(split("word. etc. ", ". "));
console.log(split(". word yep. . etc. ", ". "));
console.log(split("word", ". "));
console.log(split("word", "word"));
console.log(split("word", ""));
console.log(split("", ""));
above, idx (starting at 0) is used as the output's arr insertion pointer. The idx is incremented if the sample matches the delimiter. Also, if there's a match, we need to skip iterations i += len, to not include the delimiter in the output array.
To test, create many examples and right before return arr; use console.log(JSON.stringify(arr) === JSON.stringify(str.split(delimiter))); - it should return true for all the submitted tests.

Find Longest Prefix That is Also a Suffix in String - Javascript

Link to codewars challenge
I need to return the length of the longest prefix that is also a suffix of a string in Javascript.
As far as I understand, the prefixes in "abcd" are:
['a', 'ab', 'abc']
And the suffixes in "abcd" are:
[ 'bcd', 'cd', 'd' ]
So the length of the longest prefix that is also a suffix in "abcd" in this case is 0, because there are no prefixes that are also suffixes in "abcd".
So far I've been able to figure out how to get the suffixes into an array for comparison, but not the prefixes.
function returnLongestPrefixAndSuffix(string) {
let prefixes = [];
let suffixes = [];
for (let i = 0; i < string.length -1; i++) {
prefixes.push(string.slice(i));
}
for (let i = 1; i < string.length; i++) {
suffixes.push(string.slice(i));
}
return prefixes + " " + suffixes;
}
console.log(returnLongestPrefixAndSuffix("abcd"));
I'm not grasping the concept of how to start at the beginning of a string and add a larger element to the array each time by one character, excluding the element that would include the last one.
Please follow my current logic if possible.
EDIT: My code now looks like this:
function solve(string) {
let prefixes = [];
let suffixes = [];
let includedList = [];
for (let i = 1; i < string.length; i++) {
prefixes.push(string.slice(0, i));
}
for (let i = 1; i < string.length; i++) {
suffixes.push(string.slice(-i));
}
console.log(prefixes);
console.log(suffixes);
for (let i = 0; i < prefixes.length; i++) {
let element = prefixes[i];
if (suffixes.includes(element) === true) {
includedList.push(element);
}
}
console.log(includedList);
if (includedList.length === 0) {
return 0;
}
else {
let overlap = prefixes.filter(value => suffixes.includes(value));
console.log(overlap);
let longest = includedList.sort(function (a, b) { return b.length - a.length; })[0];
return longest.length;
}
}
console.log(solve("abcdabc"));
And this is passing 10049 test but failing 163 tests on codewars. I still do not know what to do with the overlap variable or how to exclude overlaps from the includedList array.
function solve(string) {
for (let i = Math.floor(string.length / 2); i > 0; i--) {
let prefix = string.slice(0, i);
let suffix = string.slice(-i);
if (prefix == suffix) {
return i;
}
}
return 0;
}
console.log(solve("abcdabc"));
To account for the overlap, initialize your for-loop like this:
let i = Math.floor(string.length / 2)
That will initialize the for-loop at the half-way point in your string, so that you can count down and compare whether or not the prefix == the suffix, starting with the longest.
You could return prefix.length, but that will be the same thing as i.
Also, be sure to return 0 outside of the for-loop. Because if you try:
if (prefix != suffix) {
return 0;
}
inside of the for-loop, it will stop counting right there.
To get the prefixes, you can use the second argument of .slice:
string.slice(0, i)
Note that to get the suffixes, you could also take the string from the end:
string.slice(-i)
There is no sense in collecting prefixes and suffixes in arrays, just search for the biggest i where the suffix equals the prefix.
Please see the documentation of the slice function, it may take a second argument: https://www.w3schools.com/jsref/jsref_slice_string.asp
So following your logic, one way to get prefixes would be to:
for (let i = 1; i <= string.length; i++) {
prefixes.push(string.slice(0, i));
}
EDIT:
Your newest code doesn't work because of two reasons:
You may end up with includedList being empty, but you still try to get first element out of it.
You don't take overlaps into consideration. For the input aaa the correct result is a since prefix aa overlaps with the corresponding suffix. In other words the result can't be longer than half the length of the input.

Javascript Adding leading zeros works with while loop but not for loop

I'm extracting number from a string and passing it to a function. I want to add 1 to it and then return the string while retaining the leading zeros. I was able to do it using a while loop but not a for loop. The for loop simply skips the zeros.
var addMoreZeros = (numStr)=> {
let newNumStr = (parseInt(numStr)+1).toString();
let zerosToAdd = numStr.length - newNumStr.length;
let zeroPadStr = "";
let i = 0;
while (i < zerosToAdd) {
zeroPadStr += "0";
i++;
}
//This doesn't work
//for(let i = 0; i++; i < zerosToAdd) {
// zeroPadStr+="0";
//}
return zeroPadStr + newNumStr;
}
You have your for loop syntax wrong, it should be:
(initializer; condition; increments / decrements)
so:
for(let i = 0; i < zerosToAdd; i++) {}
var addMoreZeros = (numStr)=> {
let newNumStr = (parseInt(numStr)+1).toString();
let zerosToAdd = numStr.length - newNumStr.length;
let zeroPadStr = "";
for(let i = 0; i < zerosToAdd; i++) {
zeroPadStr+="0";
}
return zeroPadStr + newNumStr;
}
console.log(addMoreZeros("00125"))
Alternative approach (instead of using for/while):
var addMoreZeros = (numStr, numLength = numStr.length) => `${++numStr}`.padStart(numLength,'0');
// example of usage
console.log(addMoreZeros("124", 5));
Explanation ++numStr coerces the numeric string to a number and increments it, then `${...}` casts the number back to a string. Finally padStart() adds leading zeros.

Whats wrong with my palindrome? (javascript)

I have written this js code for palindrome, I know there are better and more efficient palindrome methods online but I want to know why I am unable to get my palindrome function to work properly?
CODE:
var pal = function(str) {
var len = str.length;
for (var i = 0; i < len; i++) {
var comp1 = str.substring(i, i + 1);
for (var j = len; j > 0; j--) {
var comp2 = str.substring(j - 1, j);
}
if (comp1 != comp2) {
console.log("not palindrome")
break;
} else {
console.log('palindrome')
}
}
}
pal('maddog');
OUTPUT :
palindrome
not palindrome
There are lot of better algorithms to check Palindrome. Let use the similar algorithm that you are using.
We basically use two pointers - left and right, and move to middle at the same time. In the original question, left pointer and right pointer doesn't move at the same time.
Pointers should move like this -
a b c b a
^ ^
a b c b a
^ ^
a b c b a
^
var isPalindrome = function (str) {
for (var i = 0, j = str.length-1; i < j; i++ , j--) {
if (str[i] != str[j]) {
return false;
}
}
return true;
}
console.log('maddog : ' + isPalindrome('maddog'));
console.log('abcba : ' + isPalindrome('abcba'));
console.log('deed : ' + isPalindrome('deed'));
console.log('a : ' + isPalindrome('a'));
Try the following code. It works by dividing the string length by 2, and then iterating up, checking mirroring characters against each other:
var pal = function(str){
var len = str.length;
for(var i = 0; i < Math.floor(len/2); i++){
if(str[i] != str[(len-1)-i]){
return false;
}
}
return true;
}
console.log(pal("bunny"));
console.log(pal("amoreroma"));
The inner loop is totally unnecessary. It does the same thing every time -- it loops through the whole string, starting from the end, repeatedly setting comp2 to the character; when it's done, comp2 always contains the first character. So your function just tests whether every character in the string is the same as the first character.
To test if something is a palindrome, you need to compare each character with the corresponding character from the other end of the string. You don't need two loops for this. You also only need to loop through the first half of the string, not the whole string.
Finally, you should only echo Palindrome at the end of the loop. Inside the loop you only know that one character matches, not all of them.
var pal = function(str) {
var len = str.length;
var half = Math.floor(len / 2);
var isPal = true;
for (var i = 0; i < half; i++) {
var comp1 = str[i];
var comp2 = str[len - i - 1];
if (comp1 != comp2) {
console.log("not palindrome")
isPal = false;
break;
}
}
if (isPal) {
console.log('palindrome')
}
}
pal('maddog');
pal('maddam');
You don't really need the nested loops, you can just loop backwards through the string to invert the string and then compare it to the original string. I updated the Snippet to work.
Before, your code was not inverting the string but rather just iterating through the characters and assigning them to the comp1 and comp1 variables. You need to concatenate the strings in order to build the new string backwards comp = comp + str.substring(j-1, j);
var pal = function(str) {
var len = str.length;
var comp = '';
for (var j = len; j > 0; j--) {
comp = comp + str.substring(j - 1, j);
}
if (str !== comp) {
console.log("not palindrome")
return;
}
console.log('palindrome')
}
pal('arepera');

Return the first word with the greatest number of repeated letters

This is a question from coderbyte’s easy set. Many people asked about it already, but I’m really curious about what’s wrong with my particular solution (I know it’s a pretty dumb and inefficient one..)
Original question:
Have the function LetterCountI(str) take the str parameter being passed and return the first word with the greatest number of repeated letters. For example: "Today, is the greatest day ever!" should return greatest because it has 2 e's (and 2 t's) and it comes before ever which also has 2 e's. If there are no words with repeating letters return -1. Words will be separated by spaces.
My solution works most of the time. But if it seems the last word of the input isn’t valued by my code. For example, for “a bb ccc”, “bb” will be returned instead of “ccc”. But the funny thing here is if the string only contains one word, the result is correct. For example, “ccc” returns “ccc”.
Please tell me where I was wrong. Thank you in advance!
function LetterCountI(str) {
str.toLowerCase();
var arr = str.split(" ");
var count = 0;
var word = "-1";
for (var i = 0; i < arr.length; i++) {
for (var a = 0; a < arr[i].length; a++) {
var countNew = 0;
for (var b = a + 1; b < arr[i].length; b++) {
if(arr[i][a] === arr[i][b])
countNew += 1;
}
if (countNew > count) {
count = countNew;
word = arr[i];
}
}
return word;
}
}
Please find below the workable version of your code:
function LetterCountI(str) {
str = str.toLowerCase();
var arr = str.split(" ");
var count = 0;
var word = "-1";
for (var i = 0; i < arr.length; i++) {
for (var a = 0; a < arr[i].length; a++) {
var countNew = 0;
for (var b = a + 1; b < arr[i].length; b++) {
if (arr[i][a] === arr[i][b])
countNew += 1;
}
if (countNew > count) {
count = countNew;
word = arr[i];
}
}
}
return word;
}
Here is the Java code soln for your problem.
You have returned your answer incorrectly. You should have returned word/Answer/res out of "for loops".
Check my chode here.
public static String StringChallenge( String str) {
String[] arr = str.split(" ");
int count = 0; String res = "-1";
for (int i = 0; i < arr.length ; i++) {
for (int j = 0; j < arr[i].length() ; j++) {
int counter = 0;
for (int k = j + 1; k < arr[i].length() ; k++) {
if(arr[i].charAt(j) === arr[i].charAt(k) )
counter ++;
}
if (counter > count) {
count = counter; res = arr[i];
}
}
return res;
}
}
I think the problem is that you're placing the return statement inside your outermost loop. It should be inside your inner loop.
So you have to place the return statement within the inner loop.
Correct use of return
if (countNew > count) {
count = countNew;
word = arr[i];
}
return word;
}
}
}
You need to move the return word; statement outside of the loop to fix your version.
I also put together another take on the algorithm that relies on a few built in javascript methods like Array.map and Math.max, just for reference. I ran a few tests and it seems to be a few milliseconds faster, but not by much.
function LetterCountI(str) {
var maxCount = 0;
var word = '-1';
//split string into words based on spaces and count repeated characters
str.toLowerCase().split(" ").forEach(function(currentWord){
var hash = {};
//split word into characters and increment a hash map for repeated values
currentWord.split('').forEach(function(letter){
if (hash.hasOwnProperty(letter)) {
hash[letter]++;
} else {
hash[letter] = 1;
}
});
//covert the hash map to an array of character counts
var characterCounts = Object.keys(hash).map(function(key){ return hash[key]; });
//find the maximum value in the squashed array
var currentMaxRepeatedCount = Math.max.apply(null, characterCounts);
//if the current word has a higher repeat count than previous max, replace it
if (currentMaxRepeatedCount > maxCount) {
maxCount = currentMaxRepeatedCount;
word = currentWord;
}
});
return word;
}
Yet another solution in a more functional programming style:
JavaScript
function LetterCountI(str) {
return ((str = str.split(' ').map(function(word) {
var letters = word.split('').reduce(function(map, letter) {
map[letter] = map.hasOwnProperty(letter) ? map[letter] + 1 : 1;
return map;
}, {}); // map of letters to number of occurrences in the word
return {
word: word,
count: Object.keys(letters).filter(function(letter) {
return letters[letter] > 1;
}).length // number of repeated letters
};
}).sort(function(a, b) { // Sort words by number of repeated letters
return b.count - a.count;
}).shift()) && str.count && str.word) || -1; // return first word with maximum repeated letters or -1
}
console.log(LetterCountI('Today, is the greatest day ever!')); // => greatest
Plunker
http://plnkr.co/edit/BRywasUkQ3KYdhRpBfU2?p=preview
I recommend use regular expression: /a+/g to find a list of letter with a key word a.
My example :
var str = aa yyyyy bb cccc cc dd bbb;
Fist, find a list of different word :
>>> ["a", "y", "b", "c", "d"]
Use regular expression for each word in list of different word :
var word = lstDiffWord[1];
var
wordcount = str.match(new RegExp(word+'+','g'));
console.log(wordcount);
>>>>["yyyyy"]
Here is full example: http://jsfiddle.net/sxro0sLq/4/

Categories

Resources