JavaScript - simplify/shorten code - javascript

I have the following function which I would like to simplify with a for loop maybe but don't know how to do it. any help will be much appreciated. Basically, if the field value is 0 or null then my total value (field) should be 0 otherwise if the field value is from 1 until 1000 then the total value becomes 5000. For every 1000 (i.e. 1001 until 2000) my total value should increase by 50 i.e. 5050. This should continue until the field value reaches 200000 and the total is 50000.
function calc56() {
var56 = parseFloat(document.getElementById('units56').value - 0);
if (var56 == '' || var56 == 0) {
document.getElementById('amount56').value = 0;
}
else if (var56 < 1000) {
document.getElementById('amount56').value = 5000;
}
else if ((var56 > 1000) && (var56 <= 2000)) {
document.getElementById('amount56').value = 5050;
}
else if ((var56 > 2000) && (var56 <= 3000)) {
document.getElementById('amount56').value = 5100;
}
}
Thanks in advance.

function calc56() {
var el = document.getElementById('units56'); //reference the dom element
var val = +el.value; //convert to float
if (!val) { //if no value, leave untouched
} else if (val < 0) { //if value is less than 0, make it 0.
el.value = 0;
} else { //otherwise, calculate new value
var mod = Math.floor(val / 1000); //calc how many 1000s fit in the value
el.value = mod * 50 + 5000; //use at least 5000, and add 50 for every 1000
}
}
I would suggest you also change the name of the function, as it's not very useful. However, this code right here should be the most efficient you can get while still keeping it readable.
If you need more clarification, feel free to ask in a comment!

Related

Persistent Bugger - Help to get rid of some 0

I need some help with a task which is about creating a function that only accepts integer numbers to then multiply each other until getting only one digit. The answer would be the times:
Example: function(39) - answer: 3
Because 3 * 9 = 27, 2 * 7 = 14, 1 * 4 = 4 and 4 has only one digit
Example2: function(999) - answer: 4
Because 9 * 9 * 9 = 729, 7 * 2 * 9 = 126, 1 * 2 * 6 = 12, and finally 1 * 2 = 2
Example3: function(4) - answer: 0
Because it has one digit already
So trying to figure out how to solve this after many failures, I ended up coding this:
function persistence(num) {
let div = parseInt(num.toString().split(""));
let t = 0;
if(Number.isInteger(num) == true){
if(div.length > 1){
for(let i=0; i<div.length; i++){
div = div.reduce((acc,number) => acc * number);
t += 1;
div = parseInt(div.toString().split(""))
if(div.length == 1){
return t } else {continue}
} return t
} else { return t }
} else { return false }
}
console.log(persistence(39),3);
console.log(persistence(4),0);
console.log(persistence(25),2);
console.log(persistence(999),4);
/*
output: 0 3
0 0
0 2
0 4
*/
It seems I could solve it, but the problem is I don't know why those 0s show up. Besides I'd like to receive some feedback and if it's possible to improve those codes or show another way to solve it.
Thanks for taking your time to read this.
///EDIT///
Thank you all for helping and teaching me new things, I could solve this problem with the following code:
function persistence(num){
let t = 0;
let div;
if(Number.isInteger(num) == true){
while(num >= 10){
div = (num + "").split("");
num = div.reduce((acc,val) => acc * val);
t+=1;
} return t
}
}
console.log(persistence(39));
console.log(persistence(4));
console.log(persistence(25));
console.log(persistence(999));
/*output: 3
0
2
4
*/
You've got a few issues here:
let div = parseInt(num.toString().split("")); You're casting an array to a number, assuming you're trying to extract the individual numbers into an array, you were close but no need for the parseInt.
function persistence(input, count = 0) {
var output = input;
while (output >= 10) {
var numbers = (output + '').split('');
output = numbers.reduce((acc, next) {
return Number(next) * acc;
}, 1);
count += 1;
}
​
return count;
};
For something that needs to continually check, you're better off using a recurssive function to check the conditions again and again, this way you won't need any sub loops.
Few es6 features you can utilise here to achieve the same result! Might be a little too far down the road for you to jump into es6 now but here's an example anyways using recursion!
function recursive(input, count = 0) {
// convert the number into an array for each number
const numbers = `${input}`.split('').map(n => Number(n));
// calculate the total of the values
const total = numbers.reduce((acc, next) => next * acc, 1);
// if there's more than 1 number left, total them up and send them back through
return numbers.length > 1 ? recursive(total, count += 1) : count;
};
console.log(recursive(39),3);
console.log(recursive(4),0);
console.log(recursive(25),2);
console.log(recursive(999),4);
function persistance (num) {
if (typeof num != 'number') throw 'isnt a number'
let persist = 0
while(num >= 10) {
let size = '' + num
size = size.length
// Get all number of num
const array = new Array(size).fill(0).map((x, i) => {
const a = num / Math.pow(10, i)
const b = parseInt(a, 10)
return b % 10
})
console.log('here', array)
// actualiser num
num = array.reduce((acc, current) => acc * current, 1)
persist++
}
return persist
}
console.log(persistance(39))
console.log(persistance(999))
console.log() can take many argument...
So for example, console.log("A", "B") will output "A" "B".
So all those zeros are the output of your persistence function... And the other number is just the number you provided as second argument.
So I guess you still have to "persist"... Because your function always returns 0.
A hint: You are making this comparison: div.length > 1...
But div is NOT an array... It is a number, stringified, splitted... And finally parsed as integer.
;) Good luck.
Side note, the calculation you are attempting is known as the Kaprekar's routine. So while learning JS with it... That history panel of the recreational mathematic wil not hurt you... And may be a good line in a job interview. ;)
My best hint
Use the console log within the function to help you degug it. Here is your unchanged code with just a couple of those.
function persistence(num) {
let div = parseInt(num.toString().split(""));
let t = 0;
console.log("div.length", div.length)
if (Number.isInteger(num) == true) {
if (div.length > 1) {
for (let i = 0; i < div.length; i++) {
div = div.reduce((acc, number) => acc * number);
t += 1;
div = parseInt(div.toString().split(""));
if (div.length == 1) {
console.log("return #1")
return t;
} else {
continue;
}
}
console.log("return #2")
return t;
} else {
console.log("return #3")
return t;
}
} else {
console.log("return #4")
return false;
}
}
console.log(persistence(39), 3);
console.log(persistence(4), 0);
console.log(persistence(25), 2);
console.log(persistence(999), 4);

Optimizing and finding edge cases that I might have missed - 2 coding interview questions

Background - I took an online coding test and was presented with questions similar to this, I did rather poorly on it compared to the hidden grading criteria and I was hoping to get another pair of eyes to look at it and maybe help point out some of my mistakes.
Practice Test questions -
Task: Given an integer inject the number 5 into it to make the largest possible integer
Conditions: (-80000...80000) range needed to handle
Expected input: int
Expected output: int
Testcase: -999 -> -5999
80 -> 850
var lrgInt = function(num) {
var stringInt = num.toString();
for (let i = 0; i < stringInt.length; i++) {
if (stringInt.charAt(i) === "-") {
return parseInt([stringInt.slice(0, 1), '5', stringInt.slice(1)].join(''));
}else if (stringInt.charAt(i) < 5) {
return parseInt([stringInt.slice(0, i), '5', stringInt.slice(i)].join(''));
}
}
return parseInt([stringInt.slice(0, stringInt.length), '5', stringInt.slice(stringInt.length)].join(''));
};
Task: Determine the number of operations done on a number following the conditions to reduce it to 0.
Conditions:
- If the number is odd, subtract 1
- If the number is even, divide by 2
Expected input: int
Expected output: int
var operations = 0;
var numberOfSteps = function(num) {
if (num === 0){
return operations;
}else if (num % 2 == 0) {
operations++;
return numberOfSteps(num/2);
} else {
operations++;
return numberOfSteps(num-1);
}
};
For the second question, you could add one plus the result of recursion with the adjusted number without having a global counter.
function numberOfSteps(number) {
if (!number) return 0;
if (number % 2) return 1 + numberOfSteps(number - 1);
return 1 + numberOfSteps(number / 2);
}
console.log(numberOfSteps(5)); // 5 4 2 1 0
For the first question, we make the observation that if the number is positive, we want to inject the 5 before the first digit less than 5, but if it's negative then we want to inject it before the first digit greater than 5. For the second problem, we can just use a simple while loop.
function largestNum(num) {
if (num == 0) {
// this edge case is weird but I'm assuming this is what they want
return 50;
}
var negative = num < 0;
var numAsStr = Math.abs(num).toString();
var inj = -1;
for (var i = 0; i < numAsStr.length; i++) {
var cur = parseInt(numAsStr[i], 10);
if ((!negative && cur < 5) || (negative && cur > 5)) {
// we found a place to inject, break
inj = i;
break;
}
}
if (inj == -1) {
// didn't inject anywhere so inject at the end
inj = numAsStr.length;
}
return (
(negative ? -1 : 1) *
parseInt(numAsStr.substr(0, inj) + "5" + numAsStr.substr(inj))
);
}
function numSteps(num) {
var steps = 0;
while (num != 0) {
if (num % 2) {
// it's odd
num--;
} else {
num /= 2;
}
steps++;
}
return steps;
}

Why does my node's style only decrease and not increase?

Im working on a website, and I'm trying to programmatically fade an object in and out.
However when i run my loop it only subtracts the opacity from the object, when I try to add to the opacity it just stays at 0.01 for the entire 100 loops, but when it runs 100-199 it subtracts 0.01 every time.
I'm confused why its doing such...
function searched() {
var count = 0;
if (srched) {
return
} else {
let runloop = setInterval(function () {
if (count <= 99) {
document.getElementById("done").style.opacity += 0.01;
} else if (count > 99 && count <= 199) {
document.getElementById("done").style.opacity -= 0.01;
} else {
clearInterval(this)
srched = false;
}
count += 1;
}, 40)
}
}
The html code is:
<p id = "done" style="opacity: 0; color: #1a5b02;">
There's no problem with the loop, just adding to the opacity.
The problem is that += can also mean concatenation, so the opacity property gets a value of '0' + '0.01' = '00.01' for a value the first time in the loop, which is corrected to 0.01, but then you get '0.010.01' in the next iteration, which is an error.
-= does not have the problem - it cannot be a string operation, so it just does the subtraction.
Solution: make sure not to do concatenation by mistake. I think the shortest solution is to write ...opacity -= -0.01; but I'm curious if there are any shorter ones ;)
You need to use Number() to add/subtract your opacity, otherwise it is treating as string and hence your effect is not working
var srched=false;
function searched() {
var count = 0,done=document.getElementById("done");
if (srched) {
return
} else {
let runloop = setInterval(function () {
if (count <= 99) {
done.style.opacity = Number(done.style.opacity)+0.01;
} else if (count > 99 && count <= 199) {
done.style.opacity = Number(done.style.opacity)-0.01;
} else {
clearInterval(this)
srched = false;
}
count += 1;
}, 40)
}
}
searched();
<p id="done">Lorem ipsum doner inut</p>

for loop in javascript is skipping else if condition half the time

I'm was just fiddling around with javascript and I wrote function using Math.random that I thought would return a coin-flip. Then I was curious so I ran it through a loop to test how often it flips true/false. I found out my loop is skipping about half of the else if conditions, and was able to verify this by catching them in the errors var. So, why is it doing this?
var truths = 0;
var alternativetruths = 0;
var errors = 0;
function game() {
var score = Math.random()*10;
return score>5;
}
for(i=0;i<999999;i++) {
if (game() === true) {
truths++
} else if (game() === false) {
alternativetruths++
} else {
errors++
}
}
console.log("truths:",truths,"alternativetruths:",alternativetruths,"errors:",errors)
truths: 500393 alternativetruths: 249580 errors: 250026
Your code calls game() twice. If the first call isn't true, then the second might or might not be true.
Just call game() once and assign the result to a variable. Don't make explicit comparisons to true and false; if statements work off boolean values, and your function already returns one of those.
for (var i = 0; i < 999999; i++) {
var result = game();
if (result)
truths++;
else
alternativetruths++;
}
Because you're calling game twice, and thus getting two different random flags.
The minimal change is to remember the number:
for(i=0;i<999999;i++) {
var flag = game();
if (flag === true) {
truths++
} else if (flag === false) {
alternativetruths++
} else {
errors++
}
}
But a couple of other notes:
If flag is a boolean (and it is, it's the result of the > operator), then if (flag === true) is pointless. Just use if (flag). The result of the === operator is a boolean too, so if you don't trust them to be true or false, where do you stop? :-) if ((flag === true) === true)?
Separately, if (flag === false) should just be if (!flag).
If flag is a boolean (and it is), then if you have if (flag), having else if (!flag) and then else doesn't make any sense. There is no way you'll reach that final else. Just if (flag) { } else { } is all you need.
But, game isn't fair, it has a very slight bias toward returning false. Remember, the range returned by Math.random() * 10 is 0 to just under 10, so checking for > 5 means you're skipping the midpoint. Because you're dealing with very small fractional numbers, you don't notice the bias, but it's there; it would be more obvious if you rounded to whole numbers, at which point it would be roughly 40%/60% true/false. You want >= 5 for fair results.
game can rather moer succinctly be written: return Math.random() >= 0.5;.
Because you're not declaring i, you're falling prey to The Horror of Implicit Globals (that's a post on my anemic little blog). Remember to declare your variables.
Re > vs. >=, here's an example where I've rounded to whole numbers to make the effect clearer:
for (var n = 0; n < 4; ++n) {
setTimeout(test.bind(null, n, true), 200 * n);
setTimeout(test.bind(null, n, false), 200 * n + 100);
}
function test(num, gte) {
var truths = 0;
var alternativetruths = 0;
var errors = 0;
function game() {
var score = Math.floor(Math.random() * 10);
return gte ? score >= 5 : score > 5;
}
for (var i = 0; i < 999999; i++) {
var flag = game();
if (flag) {
truths++;
} else {
alternativetruths++;
}
}
showStats(num, gte, truths, alternativetruths);
}
function showStats(num, gte, truths, alternativetruths) {
var total = truths + alternativetruths; // Should be 999999 of course
var truthsPercent = (truths * 100) / total;
var altPercent = (alternativetruths * 100) / total;
console.log(num, gte ? ">=" : ">", "truths:", truths, "alternativetruths:", alternativetruths, "(" + truthsPercent.toFixed(2) + "% vs. " + altPercent.toFixed(2) + "%)");
}
.as-console-wrapper {
max-height: 100% !important;
}
You need to assign game to a var before test for its value. Otherwise, everytime yout check the value with game() you will check a new value. So it can be false at the first check and true at the second and for this reason increment your errors.
Try this:
for(i=0;i<999999;i++) {
let gameResult = game();
if (gameResult === true) {
truths++
} else if (gameResult === false) {
alternativetruths++
} else {
errors++
}
}

Delay in for-loop

I want to loop over an array and assign a color on each iteration. When the color is set, I want to delay until the next iteration before changing the color again.
This is the code I currently have but I could not create the delay between each iteration of the for-loop over the just1 array.
var colors = new Array("Good","Warning","Bad");
var crntcolor= 0;
just1=[[2.8077203491999057, -1.0756484331027858], [5.4610502752805568, -1.1574541704299315], [2.414925300315495, -1.506728995633369], [11.3143165555403673, -1.4461945021353346]];
function ChangeText()
{
document.getElementById('changeText').innerHTML = colors[crntcolor];
for(i=0; i<just1.length; i++)
{
if(just1[i][0] >= -5 && just1[i][0] <= 5)
{
crntcolor =0;
}
else if (just1[i][0] > 5 && just1[i][0] <= 10)
{
crntcolor = 1;
}
else if (just1[i][0] > 10)
{
crntcolor = 2;
}
setTimeout("ChangeText();",1000);
}
}
ChangeText();
I suppose what you want to do is loop over the array and between each element have a delay. You need to get rid of the for loop and change the text only for one element at a time:
var colors = new Array("Good","Warning","Bad");
var crntcolor= 0;
var just1 = [[2.8077203491999057, -1.0756484331027858], [5.4610502752805568, -1.1574541704299315], [2.414925300315495, -1.506728995633369], [11.3143165555403673, -1.4461945021353346]];
function ChangeText(index)
{
document.getElementById('changeText').innerHTML = colors[crntcolor];
if(just1[index][0] >= -5 && just1[index][0] <= 5)
{
crntcolor =0;
}
else if (just1[index][0] > 5 && just1[index][0] <= 10)
{
crntcolor = 1;
}
else if (just1[index][0] > 10)
{
crntcolor = 2;
}
if(index < just1.length)
{
setTimeout(function() { ChangeText(index+1); },1000);
}
}
ChangeText(0);
I'm not sure what you mean by the delay between the text specific to the array data present in just1. As far as I can tell, you have specified a fixed delay (1000). Do you mean you want a different delay based on the value of what's in your array? If so, you can alter the value in the loop:
setTimeout(function() { ChangeText(index+1); },1000 * just1[index][0]);
this would set the delay to
2.8, 5.45, 2.41 and 11.31 respectively when you loop through the array

Categories

Resources