JavaScript for loop that alternates two constants - javascript

I've been trying to use a for loop to make a code that alternates between two strings and ends with .toUpperCase , but I'm completely stuck. I'm "able" to do it with an array with two strings (and even so it has a mistake, as it ends with the first string of the array...), but not with two separate constants.
Could anyone offer some help?
function repeteFrases(num) {
const frases = ["frase um", "frase dois"];
let result = "";
for (let i = 0; i < num; i++) {
result += i === num - 1 ? frases[0].toUpperCase() : `${frases[0]}, ${frases[1]}, `;
}
return result;
}
console.log(repeteFrases(2));

In order to alternate between two states you can use the parity of the index, i.e., the condition would be i % 2 == 0, like this:
function repeteFrases(num) {
const frases = ["frase um", "frase dois"];
let result = "";
for (let i = 0; i < num; i++) {
result += i % 2 == 0 ? frases[0].toUpperCase() : `${frases[0]}, ${frases[1]}, `;
}
return result;
}
console.log(repeteFrases(5));

You've almost got it.. I think what you're asking for is to repeat phrase one or two (alternating), and for the last version to be uppercase. I notice someone else made your code executable, so I might be misunderstanding. We can test odd/even using the modulus operator (%), which keeps the access of frases to either the 0 or 1 position. The other trick is to loop until one less phrase than needed, and append the last one as upper case.
function repeteFrases(num) {
const frases = ["frase um", "frase dois"];
//Only loop to 1 less than the expected number of phrases
const n=num-1;
let result = "";
for (let i = 0; i < n; i++) {
//Note %2 means the result can only be 0 or 1
//Note ', ' is a guess at inter-phrase padding
result+=frases[i%2] + ', ';
}
//Append last as upper case
return result+frases[n%2].toUpperCase();
}
console.log(repeteFrases(2));
console.log(repeteFrases(3));

Use frases[i % frases.length] to alternate the phrases (however many there might be)
function repeteFrases(num) {
const frases = ["frase um", "frase dois"];
let result = "";
for (let i = 0; i < num; i++) {
const next = frases[i % frases.length];
const isLast = (i === num - 1);
result += isLast ? next.toUpperCase() : `${next}, `;
}
return result;
}
console.log(repeteFrases(5));

Related

How to find the longest sequence of "broken" characters using Regex in JS?

I'm trying to find the longest sequence of "broken"(different from letter, digit, space) characters in this sentence:
'Tempera####&&#^ na ##$ata 23 grad#%&.'
I really want to do it using Regex, but I'm not that familiar with the usage of Regex in JS. This is the description of the problem: https://pastebin.com/U6Uukc4b
I watched a lot of tutorials, also read bunch of articles and this is what I came up with:
let input = [
'Tempera####&&#^ na ##$ata 23 grad#%&.'
];
let print = this.print || console.log;
let gets = this.gets || ((arr, index) => () => arr[index++])(input, 0);
let message = gets();
//different from letter, digit, space
let counter = 1;
let allWords = /[a-z1-9\s]/gi;
for (let i = 0; i < message.length; i++) {
let current = message[i];
// allWords.lastIndex = 0;
let isExisting = allWords.test(current);
if (current === '.') {
break;
}
if (isExisting) {
counter = 1;
} else {
counter++;
}
}
print(counter)
Here the answer should be 8 , because we have 8 consecutive symbols inside the word "Tempera####&&#^" , which are not letter, digit or space.
Unfortunately this doesn't work. I'm still trying to understand where is my mistake, so I'll be very thankful if someone can "show me the way".
Use a regular expression that matches the opposite ([^.....]) and as many times as possible (+). Then check the size of all matches and pick the longest length. As there is a special role for the point (which apparently is always at the end), consider it as not broken.
let allWords = /[^a-z1-9\s.]+/gi;
let input = [
'Tempera####&&#^ na ##$ata 23 grad#%&.'
];
for (let message of input) {
let results = message.match(allWords) ?? [];
let counter = Math.max(0, ...results.map(({length}) => length));
console.log("longest", counter);
}
const input = 'Tempera####&&#^ na ##$ata 23 grad#%&.';
function findLongestSubstring(input) {
let longest = '';
let current = '';
for (let i = 0; i < input.length; i++) {
if (input[i].match(/[^a-zA-Z\d\s]/)) {
current += input[i];
} else {
if (current.length > longest.length) {
longest = current;
}
current = '';
}
}
return longest.length;
}
console.log(findLongestSubstring(input));

function that randomly sorts through letters and changes them not working

I am making a javascript function that will input a string, and output a "spongebob mocking text"
basically, you input "Hello, this is a message to the world" and you would get "HeLlO, ThIS iS a MeSsAGe tO tHE wORlD"
basically, randomly decide wheather to capitalize a letter or not. I made a function which i thought would do that, but it didn't work. here is the code that I tested in the js console:
function memify(input) { // function called memify()
var il = input.length; // gets the length of the input
var newinput = input; // creates a new variable that will be changed from input.
for (var i=0;i>il;i++) {
var rng = Math.floor((Math.random()*2)); // random number between 0 and 1. 0 = upper 1 = lower
if (rng === 0) {
newinput.charAt(i).toUpperCase();
}
else {
newinput.charAt(i).toLowerCase();
}
}
return newinput;
}
var text = prompt();
var textmeme = memify(text);
alert(textmeme);
Why is this not working? Do I have an error in my code? Any help will be greatly appreciated.
When you do
newinput.charAt(i).toUpperCase();
you're creating a new uppercase character, but you aren't doing anything with it; it's just an unused expression, so there's no visible change. Primitives (including strings) are immutable - you should explicitly reassign a string to something else (eg newString += newinput.charAt(i).toUpperCase();) to see an effect.
You also need to use
for (var i = 0; i < il; i++) {
// ^
instead of
for (var i = 0; i > il; i++) {
// ^
else, no iterations will run at all.
function memify(input) { // function called memify()
var il = input.length; // gets the length of the input
let changedStr = '';
for (var i = 0; i < il; i++) {
var rng = Math.floor((Math.random() * 2)); // random number between 0 and 1. 0 = upper 1 = lower
if (rng === 0) {
changedStr += input.charAt(i).toUpperCase();
} else {
changedStr += input.charAt(i).toLowerCase();
}
}
return changedStr;
}
var text = prompt();
var textmeme = memify(text);
console.log(textmeme);
Another option, using .map, which looks much cleaner IMO:
const memify = input => [...input]
.map(char => Math.random() < 0.5 ? char.toUpperCase() : char.toLowerCase())
.join('');
console.log(memify(prompt()));
Or more concise, safer and generally better solution :). It does not require for loop, checking length of string and other error prone stuff.
function memify(input) {
var rng = () => Math.random() > 0.5;
var res = input.split('').map( letter =>
rng() ? letter.toUpperCase() : letter.toLowerCase()
).join('');
return res;
}
var textmeme = memify("Hello World");
console.log(textmeme);
Please up-vote if it was helpful :)

Find minimum concat number of two strings

Alice has two strings, initial and goal. She can remove some number of characters from initial, which will give her a subsequence of that string. A string with no deletions is still considered a subsequence of itself. Given these two strings, can you find the minimum number of subsequences of initial that, when appended together, will form goal?
Functions
minimumConcat() has two parameters:
initial: the source string that you will get subsequences from
goal: the target string that needs to be formed
Input Format
For some of our templates, we have handled parsing for you. If we do not provide you a parsing function, you will need to parse the input directly. In this problem, our input format is as follows:
The first line is the initial String that we will be generating subsequences from
The second line is the goal String to form
Here is an example of the raw input:
abc
bcbac
Expected Output
Return the number of minimum possible subsequences of initial that can be appended together to form goal.
If there are no possible solutions, return -1.
Example minimumConcat() Input #1
initial: "xyz"
goal: "xzyxz"
Output: 3
function minimumConcat(initial, goal) {
//Put your code here.
return 0;
}
Loop the initial string array to form the goal string array.
function minimumConcat(initial, goal) {
initial = initial.split('');
goal = goal.split('');
let res,count=0;
while(true){
if(goal.length > 0){
res = checkChar(initial,goal);
if(false === res){
return -1;
}
}else{
return count;
}
goal = res;
count++;
}
}
function checkChar(initial,goal){
let started = false;
let foundIndex = 0;
for(let i=0; i<initial.length; i++){
if(initial[i] == goal[foundIndex]){
started = true;
foundIndex++;
}
}
if(started){
return goal.slice(foundIndex);
}else{
return false;
}
}
console.log(minimumConcat('abc','bcbac'));
Here you go!
function minimumConcat(initial, goal) {
let result = 0;
let pattern = '';
let count1 = Array.apply(null, Array(26)).map(Number.prototype.valueOf, 0);
let count2 = Array.apply(null, Array(26)).map(Number.prototype.valueOf, 0);
initial.split('').forEach(c => {
pattern = pattern + c
});
pattern = "^[" + pattern + "]*$";
if (!RegExp(pattern).test(goal)) return -1;
for (let i = 0; i < initial.length; i++) {
count1[initial.charCodeAt(i) - 97]++;
}
for (let i = 0; i < goal.length; i++) {
count2[goal.charCodeAt(i) - 97]++;
}
for (let i = 0; i < 26; i++) {
result += Math.abs(count1[i] - count2[i]);
}
return result;
}
console.log(minimumConcat("abc", "bcbac"));
Since this looks like homework I won't give the solution right away, instead here is a suggestion on how to solve it:
I think the hardest part is finding all the sub-strings if you are using Python that's simplified by itertools as mentioned here.
Edit, I didn't notice the javascript tag, you can get the substring set, without a library, with a couple of for loops.
After having all combinations from initial you can sort them to have the longest first. And then go one by one removing them from goal. Counting every time you remove. If, after iterating over all sub-strings, goal is not an empty string then no subsequence of initial can construct goal.
This answers your question using Java
public static int minimumConcat(String initial, String goal) {
HashSet<Character> set = new HashSet<>();
for(char c : initial.toCharArray()) set.add(c);
for(char c : goal.toCharArray()) {
if(!set.contains(c)) return -1;
}
int j = 0, result = 0;
for(int i = 0; i < goal.length();) {
char c = goal.charAt(i);
while(j < initial.length() && initial.charAt(j) != c) j++;
if(j == initial.length()) {
j = 0;
result++;
} else {
j++;
i++;
}
}
result++;
return result;
}
Here is what I've done with python
def minimumConcat(initial, goal):
#verify that goal has all character of initial
res = 0
for i in goal:
if i in initial:
pass
else:
res=-1;
if res != -1:
while goal!="":
a = removefirstGreatestSubstring(initial,goal)
goal=a["goal"];
if a["has"] ==True :
res=res+1
#find the greatest concat
print(res)
def removefirstGreatestSubstring(initial,goal):
has_subtring = False
start = 0
for car in initial:
if car == goal[start]:
has_subtring= True
start = start+1
finalgoal=goal[start:]
return {"goal": finalgoal, "has":has_subtring}
initial = "abc"
goal = "bcbac"
b = minimumConcat(initial, goal)
I've made it using a different approach with regular expressions.
Here a clean version of the code:
"use strict";
// Solution:
function minimumConcat(initial, goal) {
let result = -1;
let goal_slice = goal;
let exp = "", sub = "";
let initial_concat = "";
let matches = 0, count = 0;
let initial_arr = initial.split('');
for(let i = 0 ; i<initial_arr.length; i++){
for(let j = initial_arr.length ; j>i+1; j--){
sub = initial.slice(i,j);
exp = new RegExp(sub,"ig");
matches = (goal_slice.match(exp) || []).length;
if(matches>=1) {
count +=matches;
initial_concat+=sub.repeat(matches);
goal_slice = goal_slice.slice((goal_slice.lastIndexOf(sub)+sub.length));
}
}
}
result = (initial_concat==goal)? count : result;
return result;
}
// Test cases:
let test_cases = [
{initial:"abc", goal: "abcbc"}, // expected result 2
{initial:"abc", goal: "acdbc"}, // expected result -1
{initial:"bcx", goal: "bcbcbc"}, // expected result 3
{initial:"xyz", goal: "xyyz"}, // expected result 2
]
// Running the tests:
test_cases.forEach(function(item,index){
console.log(minimumConcat(item.initial, item.goal));
});
Also, I've included a debug flag to turn on/off console.log messages in order to anybody could easily understand what is happening on each iteration cycle.
"use strict";
// Shwitch for debugging:
const debug = true;
// Solution:
function minimumConcat(initial, goal) {
let exp = "";
let sub = "";
let match = 0;
let count = 0;
let result = -1;
let goal_slice = goal;
let initial_concat = "";
let initial_arr = initial.split('');
for(let i = 0 ; i<initial_arr.length; i++){
for(let j = initial_arr.length ; j>i+1; j--){
sub = initial.slice(i,j);
exp = new RegExp(sub,"ig");
match = (goal_slice.match(exp) || []).length;
if(match>=1) {
count +=match;
initial_concat+=sub.repeat(match);
goal_slice = goal_slice.slice((goal_slice.lastIndexOf(sub)+sub.length));
}
if(debug){
console.log("-----------------------------");
console.log(" i:", i, " - j:", j);
console.log(" exp:", exp);
console.log(" goal:", goal);
console.log(" goal_slice:", goal_slice);
console.log(" match:",match);
}
}
}
result = (initial_concat==goal)? count : result;
if(debug){
console.log("---RESULTS:--------------------------");
console.log("count:",count);
console.log("goal vs initial_concat: ", goal, " - ", initial_concat);
console.log("result: ", result);
}
return result;
}
// Test cases:
let test_cases = [
{initial:"abc", goal: "abcbc"}, // expected result 2
{initial:"abc", goal: "acdbc"}, // expected result -1
{initial:"bcx", goal: "bcbcbc"}, // expected result 3
{initial:"xyz", goal: "xyyz"}, // expected result 2
]
// Running the tests:
test_cases.forEach(function(item,index){
if(debug){
console.log("-----------------------------");
console.log("TEST CASE #",index,":");
console.table(item);
}
minimumConcat(item.initial, item.goal);
});
here is in php
public function index()
{
$init="abc";
$goal="abacabacabacacb";
$res=$this->minimum($init,$goal);
}
public function check($inital,$goal){
$inital=str_split( $inital);
$goal=str_split( $goal);
for($i=0;$i<sizeof($goal);$i++){
if(!in_array($goal[$i],$inital)){
return -1;
}
}
return 0;
}
public function minimum($inital,$goal){
$res=$this->check($inital,$goal);
if($res==-1){
return -1;
}
$counter=0;
$c=0;
$inital=str_split( $inital);
$goal=str_split( $goal);
for($i=0;$i<sizeof($goal);$i++){
for($j=0;$j<sizeof($inital);$j++){
if(($i+$c)<sizeof($goal)){
echo " ".$i." > ".$j." > ".$c." /// ";
if($goal[$i+$c]==$inital[$j]){
$c+=1;
}
}
}
$counter+=1;
if(($i+$c)>=sizeof($goal)){
break;
}
$c=$c-1;
}
return $counter;
}
Here is my python solution
def check_char(initial, goal):
N = len(initial)
started = False
found_index = 0
for i in range(N):
if (initial[i] == goal[found_index]):
started = True
found_index += 1
if(started):
return goal[found_index:]
else:
return '-'
def minimumConcat(initial, goal):
res = 0
count = 0
while(True):
if( len(goal) > 0 ):
res = check_char(initial, goal)
if(res == '-'):
print(-1)
break;
else:
print(count)
break;
goal = res
count += 1
initial = input()
goal = input()
minimumConcat(initial, goal)

HackerRank problem PlusMinus using for-loop

I need very specific answer to this particular HackerRank problem : https://www.hackerrank.com/challenges/plus-minus/problem.
Why this code is passing all the test-cases ?
function plusMinus(arr) {
let positives = 0
let negatives = 0
let zeros = 0
const length=arr.length
for (var i = 0; i < arr.length;i++){
if (arr[i] > 0) {
positives++
} else if (arr[i] < 0) {
negatives++
} else {
zeros ++
}
}
const positiveRatio = Number(positives / length).toFixed(6)
const negativeRatio = Number(negatives / length).toFixed(6)
const zeroRatio = Number(zeros / length).toFixed(6)
console.log(positiveRatio)
console.log(negativeRatio)
console.log(zeroRatio)
}
And why this code is not passing any test-case ?
(I have edited my code: sorry for earlier wrong code) This code also does not works.
function plusMinus(arr) {
var l = arr.length;
var positiveCounter = 0;
var negativeCounter = 0;
var zeroCounter = 0;
for(var i=0; i<=l; i++) {
if (arr[i]>0) {
positiveCounter+=1;
} else if (arr[i]<0) {
negativeCounter+=1;
} else {
zeroCounter+=1;
}
}
console.log (
(positiveCounter/l).toFixed(6)+ '\n' +(negativeCounter/l).toFixed(6)+ '\n' +(zeroCounter/l).toFixed(6) );
}
I don't want alternative ways to solve this. I just want to know why the first code works and the second code doesnt ???
These 2 codes are different, you are dividing the numbers by the length twice
First in the assignment to a variable (var p= ...)
Second when doing the console.log ((p/l).toFixed(6))
Also, like mentionned by #DhananjaiPai, they have multiple console.log and you only have one with breaking characters which can be differently interpreted by OS (\r\n or \n )
You also have a something wrong in your loop, I will let you find that one but remember that an array begin from the index 0, if the array has 3 elements, that will be [0, 1, 2]

Removing zeros after comma based on maximum consequent zeros

I have a page with a grid where user's numbers get saved. It has a following pattern - every number ends with 3 digits after comma. It doesn't look nice, when for example user's input is
123,450
123,670
123,890
It's much better to have just 2 numbers after comma, because last 0 is absolutely meaningless and redundant.
The way it still should have 3 digits is only if at least one element in an array doesn't end up with 0
For example:
123,455
123,450
123,560
In this case 1st element of the array has the last digit not equal to 0 and hence all the elements should have 3 digits. The same story with 2 or 1 zeros
Zeros are redundant:
123,30
123,40
123,50
Zeros are necessary:
123,35
123,40
123,50
The question is how can I implement it programatically? I've started like this:
var zeros2Remove = 0;
numInArray.forEach(function(item, index, numInArray)
{
var threeDigitsAfterComma = item.substring(item.indexOf(',') + 1);
for(var j = 2; j <= 0; j--)
{
if(threeDigitsAfterComma[j] == 0)
{
zeros2Remove =+ 1;
}
else //have no idea what to do..
}
})
Well in my implementation I don't know how to do it since I have to iterate through every element but break it if at least 1 number has a last digit equal to zero.. In order to do that I have to break outer loop, but don't know how and I'm absolutely sure that I don't have to...
I think the following code what you are looking for exactly , please manipulate numbers and see the changes :
var arr = ["111.3030", "2232.0022", "3.001000", "4","558.0200","55.00003000000"];
var map = arr.map(function(a) {
if (a % 1 === 0) {
var res = "1";
} else {
var lastNumman = a.toString().split('').pop();
if (lastNumman == 0) {
var m = parseFloat(a);
var res = (m + "").split(".")[1].length;
} else {
var m = a.split(".")[1].length;
var res = m;
}
}
return res;
})
var maxNum = map.reduce(function(a, b) {
return Math.max(a, b);
});
arr.forEach(function(el) {
console.log(Number.parseFloat(el).toFixed(maxNum));
});
According to MDN,
There is no way to stop or break a forEach() loop other than by throwing an exception. If you need such behavior, the forEach() method is the wrong tool. Use a plain loop or for...of instead.
If you convert your forEach loop to a for loop, you can break out of it with a label and break statement:
// unrelated example
let i;
let j;
outerLoop:
for (i = 2; i < 100; ++i) {
innerLoop:
for (j = 2; j < 100; ++j) {
// brute-force prime factorization
if (i * j === 2183) { break outerLoop; }
}
}
console.log(i, j);
I gave you an unrelated example because your problem doesn't need nested loops at all. You can find the number of trailing zeroes in a string with a regular expression:
function getTrailingZeroes (str) {
return str.match(/0{0,2}$/)[0].length;
}
str.match(/0{0,2}$/) finds between 0 and 2 zeroes at the end of str and returns them as a string in a one-element array. The length of that string is the number of characters you can remove from str. You can make one pass over your array of number-strings, breaking out when necessary, and use Array.map as a separate truncation loop:
function getShortenedNumbers (numInArray) {
let zeroesToRemove = Infinity;
for (const str of numInArray) {
let candidate = getTrailingZeroes(str);
zeroesToRemove = Math.min(zeroesToRemove, candidate);
if (zeroesToRemove === 0) break;
}
return numInArray.map(str => str.substring(0, str.length - zeroesToRemove);
}
All together:
function getTrailingZeroes (str) {
return str.match(/0{0,2}$/)[0].length;
}
function getShortenedNumbers (numInArray) {
let zeroesToRemove = Infinity;
for (const str of numInArray) {
let candidate = getTrailingZeroes(str);
zeroesToRemove = Math.min(zeroesToRemove, candidate);
if (zeroesToRemove === 0) break;
}
return numInArray.map(str => str.substring(0, str.length - zeroesToRemove));
}
console.log(getShortenedNumbers(['123,450', '123,670', '123,890']));
console.log(getShortenedNumbers(['123,455', '123,450', '123,560']));
This solution might seem a little cumbersome but it should work for all possible scenarios. It should be easy enough to make always return a minimal number of decimals places/leading zeros.
I hope it helps.
// Define any array
const firstArray = [
'123,4350',
'123,64470',
'123,8112390',
]
const oneOfOfYourArrays = [
'123,30',
'123,40',
'123,50',
]
// Converts 123,45 to 123.45
function stringNumberToFloat(stringNumber) {
return parseFloat(stringNumber.replace(',', '.'))
}
// For 123.45 you get 2
function getNumberOfDecimals(number) {
return number.split('.')[1].length;
}
// This is a hacky way how to remove traling zeros
function removeTralingZeros(stringNumber) {
return stringNumberToFloat(stringNumber).toString()
}
// Sorts numbers in array by number of their decimals
function byNumberOfValidDecimals(a, b) {
const decimalsA = getNumberOfDecimals(a)
const decimalsB = getNumberOfDecimals(b)
return decimalsB - decimalsA
}
// THIS IS THE FINAL SOLUTION
function normalizeDecimalPlaces(targetArray) {
const processedArray = targetArray
.map(removeTralingZeros) // We want to remove trailing zeros
.sort(byNumberOfValidDecimals) // Sort from highest to lowest by number of valid decimals
const maxNumberOfDecimals = processedArray[0].split('.')[1].length
return targetArray.map((stringNumber) => stringNumberToFloat(stringNumber).toFixed(maxNumberOfDecimals))
}
console.log('normalizedFirstArray', normalizeDecimalPlaces(firstArray))
console.log('normalizedOneOfOfYourArrays', normalizeDecimalPlaces(oneOfOfYourArrays))
Try this
function removeZeros(group) {
var maxLength = 0;
var newGroup = [];
for(var x in group) {
var str = group[x].toString().split('.')[1];
if(str.length > maxLength) maxLength = str.length;
}
for(var y in group) {
var str = group[y].toString();
var substr = str.split('.')[1];
if(substr.length < maxLength) {
for(var i = 0; i < (maxLength - substr.length); i++)
str += '0';
}
newGroup.push(str);
}
return newGroup;
}
Try it on jsfiddle: https://jsfiddle.net/32sdvzn1/1/
My script checks the length of every number decimal part, remember that JavaScript removes the last zeros in a decimal number, so 3.10 would be 3.1, so the length is less when there is a number with zeros in the end, in this case we just add a zero to the number.
Update
I've updated the script, the new version adds as much zeros as the different between the max decimal length and the decimal length of the analyzed number.
Example
We have: 3.11, 3.1423, 3.1
The max length would be: 4 (1423)
maxLenght (4) - length of .11 (2) = 2
We add 2 zeros to 3.11, that will become 3.1100
I think you can start out assuming you will remove two extra zeros, and loop through your array looking for digits in the last two places. With the commas, I'm assuming your numArray elements are strings, all starting with the same length.
var numArray = ['123,000', '456,100', '789,110'];
var removeTwo = true, removeOne = true;
for (var i = 0; i < numArray.length; i++) {
if (numArray[i][6] !== '0') { removeTwo = false; removeOne = false; }
if (numArray[i][5] !== '0') { removeTwo = false; }
}
// now loop to do the actual removal
for (var i = 0; i < numArray.length; i++) {
if (removeTwo) {
numArray[i] = numArray[i].substr(0, 5);
} else if (removeOne) {
numArray[i] = numArray[i].substr(0, 6);
}
}

Categories