how to get consecutive value of a changing object in javascript - javascript

I am New to Programming, and want to write a simple code that will allow me to get consecutive value from a live feed strings from server, where I need help is how to do below task
First, let me make an example
Like getting a live price update of Dash coin - let's says price is currently
#1- $55, then it changes to
#2- $56, then it changes to
#3- $57, then it changes to
#4- $58, then it changes to
#5- $54, now it's no longer consecutive
The above shows a #4 consecutive increase in Price value
My question is How to set this function
#how to get changing values when it increases or decreases conservatively a number of times!
For instance, if I want to get an alert when the Dash Price increases consecutively #4 times or more in a row or any x number of times
Will appreciate a guide on how to go about this in JavaScript.
//ok first I tried the above BELOW, but I didn't get the expected results - how I used it below: What did I do wrong?
const WebSocket = require('ws');
var ws = new WebSocket('wss://ws.binaryws.com/websockets/v3?app_id=1089');
var lastTick = null;
ws.onopen = function(evt) {
ws.send(JSON.stringify({ticks:'R_100'}));
};
ws.onmessage = function(msg) {
var data = JSON.parse(msg.data);
var currentTickTime = data.tick.epoch;
var currentTick = data.tick.quote;
const timerz = 1000;
//console.log(currentTick,'\n', balance)
var tickTime = new Date(currentTickTime * timerz).toLocaleString();
//testing code below
function handleNotification(){
if (balance > 3){
console.log("RISE UP-3times.");
// Send notification that price is rising.
}
if (balance < -3){
console.log("FALL DOWN-3times.");
// Send notification that price is falling.
}
}
var currentPrice = 0;
var balance = 0;
setInterval(async () => {
const previousPrice = currentPrice;
currentPrice = await currentTick;
if (currentPrice > previousPrice){
//console.log('Higher Price')
if (balance >= 0) balance++
else balance = 0;
}else if (currentPrice < previousPrice){
//console.log('Lower Price')
if (balance <= 0) balance--
else balance = 0;
}else{
// Price remains unchanged.
}
handleNotification();
console.log(currentPrice,'\n', balance)
}, 2000);
lastTick = currentTick;
};
I also tried the second option below but, the highest - num_consec value was 1 & -1, even when there are multiple consecutive higher than that.
Below is the code used:
const WebSocket = require('ws');
var ws = new WebSocket('wss://ws.binaryws.com/websockets/v3?app_id=1089');
////////////////////////////////////////////////////
var lastTick = null;
var lastTickTime = null;
ws.onopen = function(evt) {
ws.send(JSON.stringify({ticks:'R_100'}));
};
ws.onmessage = function(msg) {
var data = JSON.parse(msg.data);
var currentTickTime = data.tick.epoch;
var currentTick = data.tick.quote;
const timerz = 1000;
//console.log(currentTick,'\n', balance)
var tickTime = new Date(currentTickTime * timerz).toLocaleString();
//console.log('ticks update: %o', currentTick, '\n', '-----------------------',tickTime);
//testing code below
////////////////////////////////////////////////////////////////////
var price = lastTick; // or whatever initial value
var num_consec = 0;
var positive = true; //needs default
setInterval(function() {
var newprice = currentTick; // code to grab price from source, edit this to grab from your api
if (Math.abs(price - newprice) >= 1) { // detect within a certain range, OP specified 1
if (price - newprice > 0 && positive) { // consecutive up
num_consec += 1;
} else if (price - newprice < 0 && !(positive)) { // consecutive down
num_consec += 1;
} else if (price - newprice < 0 && positive) { // went down and broke streak
num_consec = 0;
positive = false;
} else if (price - newprice > 0 && !(positive)) { //went up and broke streak
num_consec = 0;
positive = true;
};
price = newprice; //reset price delta
console.log("Updated Info:",'\n', price, num_consec)// update price in html or elsewhere, console.log unnecessary
if (num_consec > 2) {
// do something with consec info
console.log((positive) ? `Consecutive ${num_consec} times `+"up" : `Consecutive ${num_consec} times `+"down")
};
};
newprice = null; // reset variable
}, 1000); // check new price every 1000 ms (1s)
//console.log(currentTick,'\n', num_consec)
lastTick = currentTick;
lastTickTime = tickTime;
};
will appreciate all the help I can get- Please kindly help me check the code to know what i did wrong

Quick and easy answer here.
function handleNotification(){
if (balance > 3){
// Send notification that price is rising.
}
if (balance < -3){
// Send notification that price is falling.
}
}
var currentPrice = 0;
var balance = 0;
setInterval(async () => {
const previousPrice = currentPrice;
currentPrice = await getDashPrice();
if (currentPrice > previousPrice){
if (balance >= 0) balance++
else balance = 0;
}else if (currentPrice < previousPrice){
if (balance <= 0) balance--
else balance = 0;
}else{
// Price remains unchanged.
}
handleNotification();
}, 60000);
Nothing complicated. We just track the price. If the price is lower than when we last checked, we decrease the balance value. If it's higher, we increase it. If the balance value is positive and the price decreases, we set it back to 0 because it's no longer consecutive. And then vice versa.
Balance simply tracks how many negative or positive consecutive results occurred. This doesn't do much for you if the price change is very small though. You would need to add a threshold to the if statement if you'd like to make it less finely controlled.
Edit: Here's how you would do a threshold.
var currentPrice = 0;
var balance = 0;
const threshold = 0.01; // 1%
setInterval(async () => {
const previousPrice = currentPrice;
const currentPriceTemp = await getDashPrice();
if (currentPriceTemp > (previousPrice * (1 + threshold))){
if (balance >= 0) balance++
else balance = 0;
currentPrice = currentPriceTemp;
}else if (currentPriceTemp < (previousPrice * (1 - threshold))){
if (balance <= 0) balance--
else balance = 0;
currentPrice = currentPriceTemp;
}else{
// Price remains unchanged.
}
handleNotification();
}, 60000);
That will multiply the previous price by 1.01 or 0.99 depending on if we're testing higher or lower. Basically the price change needs to be more than 1% higher or lower than the previous value. In this example, I also don't set currentPrice if the change didn't meet the 1% criteria. This avoids creeping if the change is less than 1% (e.g. it rises 0.5% 100 times in a row, the consecutive function would never trigger).
You can modify threshold variable to whatever you want and the code will only consider it consecutive if the value rises or falls by that percentage. const threshold = 0.01; is 1% and const threshold = 0.99; is 99%.

I would recommend doing this the following way to avoid blocking your thread, but periodically keep checking for a specific range of change. Unfortunately measuring consecutive change is not super simple but can be done with the code below.
Possible implementation of setInterval():
var price = 50; // or whatever initial value
var num_consec = 0;
var positive = true; //needs default
setInterval(function() {
var newprice = ...; // code to grab price from source, edit this to grab from your api
if (Math.abs(price - newprice) >= 1) { // detect within a certain range, OP specified 1
if (price - newprice > 0 && positive) { // consecutive up
num_consec += 1;
} else if (price - newprice < 0 && !(positive)) { // consecutive down
num_consec += 1;
} else if (price - newprice < 0 && positive) { // went down and broke streak
num_consec = 0;
positive = false;
} else if (price - newprice > 0 && !(positive)) { //went up and broke streak
num_consec = 0;
positive = true;
};
price = newprice; //reset price delta
console.log("Updated Info:", price, num_consec)// update price in html or elsewhere, console.log unnecessary
if (num_consec > 2) {
// do something with consec info
console.log((positive) ? `Consecutive ${num_consec} times `+"up" : `Consecutive ${num_consec} times `+"down")
};
};
newprice = null; // reset variable
}, 1000); // check new price every 1000 ms (1s)
Test Cases (Ouput):
Increasing:
Test price Value:47
file.html:24 Updated Info: 47 0
file.html:40 Test price Value:46
file.html:24 Updated Info: 46 0
file.html:40 Test price Value:45
file.html:24 Updated Info: 45 1
file.html:40 Test price Value:44
file.html:24 Updated Info: 44 2
file.html:40 Test price Value:43
file.html:24 Updated Info: 43 3
file.html:28 Consecutive 3 times up
file.html:40 Test price Value:44
file.html:24 Updated Info: 44 0
file.html:40 Test price Value:43
file.html:24 Updated Info: 43 0
Decreasing:
file.html:40 Test price Value:64
file.html:24 Updated Info: 64 0
file.html:40 Test price Value:65
file.html:24 Updated Info: 65 0
file.html:40 Test price Value:66
file.html:24 Updated Info: 66 1
file.html:40 Test price Value:67
file.html:24 Updated Info: 67 2
file.html:40 Test price Value:68
file.html:24 Updated Info: 68 3
file.html:28 Consecutive 3 times down
file.html:40 Test price Value:69
file.html:24 Updated Info: 69 4
file.html:28 Consecutive 4 times down
file.html:40 Test price Value:70
file.html:24 Updated Info: 70 5
file.html:28 Consecutive 5 times down
file.html:40 Test price Value:71
file.html:24 Updated Info: 71 6
file.html:28 Consecutive 6 times down
file.html:40 Test price Value:70
file.html:24 Updated Info: 70 0
file.html:40 Test price Value:69
file.html:24 Updated Info: 69 1
If this did not answer your question, or you’d like additional help, please direct message me so we can work through your issue.

Related

Leetcode 322: Coin change with 2 programming languages produces 2 different results

I am trying to solve Leetcode Problem 322. Here's the description quoted from the site.
You are given an integer array coins representing coins of different denominations and an integer amount representing a total amount of money.
Return the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1.
You may assume that you have an infinite number of each kind of coin.
I have written 2 recursive solutions, 1 in Python and 1 in Javascript. For some reason, the one in Javascript doesn’t produce the correct values for the same input, while the Python one always do.
Would like to ask if anyone knows what could be the reason for the difference in output. I tried with the following test cases:
coins = [1,2,5], amount = 11 => Expected: 3
coins = [1,2], amount = 2 => Expected: 1
Here's the code I've written in the respective languages.
Javascript
var coinChange = function(coins, amount) {
coins = coins.sort((a,b) => b -a )
ans = helper(coins, amount, 0)
if (ans >= Number.MAX_VALUE) {
return -1
}
return ans;
};
function helper(coins, amount, pos) {
if (pos >= coins.length || amount < 0) {
return Number.MAX_VALUE;
} else if (amount === 0) {
return 0;
}
left = helper(coins, amount - coins[pos], pos) + 1
right = helper(coins, amount, pos + 1)
return Math.min(left, right)
}
Using the above 2 test cases, it gets both test cases wrong.
coins = [1,2,5], amount = 11 => Expected: 3, gets 2
coins = [1,2], amount = 2 => Expected: 1, gets 2
Python
def coinChange(coins, amount):
coins = sorted(coins, reverse = True)
ans = helper(coins, amount, 0)
if (ans >= float("inf")):
return -1
return ans
def helper(coins, amount, pos):
if (pos >= len(coins) or amount < 0):
return float("inf")
elif (amount == 0):
return 0
left = helper(coins, amount - coins[pos], pos) + 1
right = helper(coins, amount, pos + 1)
return min(left, right)
Using the above 2 test cases, it gets both tests correct.
coins = [1,2,5], amount = 11 => Expected: 3, gets 3
coins = [1,2], amount = 2 => Expected: 1, gets 1
The Javascript code gets the expected answer by adding let to the return values to each of the recursive calls.
For example, left = helper(coins, amount - coins[pos], pos) + 1 is changed to
let left = helper(coins, amount - coins[pos], pos) + 1

NaN in the context of a recursive for loop

I am trying to understand a solution I found for a problem: "You are given coins of different denominations and a total amount of money. Write a function to compute the number of combinations that make up that amount. You may assume that you have infinite number of each kind of coin."
My question is, if I run the function with change(3,[2]), why does it spit out 0. I am having trouble with comprehending how after a single recursive call currentCoin becomes undefined, and then when the program reaches the for loop in that call, it doesn't call the change function again with total += change(amount - 0 * undefined, coins.slice(0, -1)). Why does it not crash with either an infinite recursive call with change(NaN,[]) or coins.slice(0,-1) being used on an empty array. It seems to ignore that on the for loop.
Am I misunderstanding how a for-loop works?
var change = function(amount, coins) {
if(amount == 0) return 1;
let currentCoin = coins[coins.length - 1];
let total = 0;
for(let qty = 0; qty * currentCoin <= amount; qty++){
total += change(amount - qty * currentCoin, coins.slice(0, -1))
}
return total;
};
console.log(change(3,[2]))
There are a couple things going on here.
First is the behavior of coins[coins.length - 1]. In Javascript, when you access an element of a list at an index that doesn't exist in that list, the indexer will return undefined instead of crashing with an IndexOutOfBoundsException or the like.
Second is qty * currentCoin <= amount. In the case that currentCoin is undefined (due to the above), qty * currentCoin will be NaN. In Javascript, any comparison of NaN with another number will return false by design. (e.g. NaN <= anything is false).
Put this all together and you see that, on the first recursion, the coins array will be empty which makes currentCoin NaN. This causes qty * currentCoin <= currentAmount to be false, which causes the loop to short circuit (so slice never gets called on an empty list). Since the loop never executes, total will still be 0, which is what gets returned. This continues until qty * currentCoin <= amount becomes true in the outermost recursion, and that loop exits with total still equalling 0 (since it only ever added 0).
If you intersperse console.log calls in strategic places about the function, it becomes clearer what is happening:
var change = function(amount, coins) {
console.log(amount, coins);
if(amount == 0) return 1;
let currentCoin = coins[coins.length - 1];
console.log(':', currentCoin, amount);
let total = 0;
for(let qty = 0; qty * currentCoin <= amount; qty++){
total += change(amount - qty * currentCoin, coins.slice(0, -1))
console.log('=', total);
}
console.log('recdone');
return total;
};
console.log(change(3,[2]))
not crash because a NaN in comparison with a number is every false...
NaN < number or NaN > number and so on produce false... so the
qty * currentCoin <= amount
is evaluate false and will exit from the for.
So, if you need to check the NaN you must before the for
let totalCoin = qty * currentCoin;
let check = isNaN(totalCoin);
if(check) {
// return you sentinel value;
}
var change = function(amount, coins) {
if(amount == 0) return 1;
let currentCoin = coins[coins.length - 1]; // firstpass 1-1 = 0, second pas 0-1=-1 => coins[-1] = undefined
let total = 0;
// this will 0*0<=3, second pass 0*undefined => null which is false hence never execute
for(let qty = 0; qty * currentCoin <= amount; qty++){
total += change(amount - qty * currentCoin, coins.slice(0, -1))
}
return total;
};
console.log(change(3,[2]))
In second pass when coins.length = 0 then
let currentCoin = coins[0 - 1]; // = undefined
Later in for loop you will 0 * undefined ( qty * currentCoin) which results NaN which is Not a number
There is no need for recursion in this case. One can use a bottom-up dynamic programming approach. Let ways[i] denote the number of ways to get to i dollars with the given coins and coins[i] represent the value of the ith coin. Then, ways[i] is the sum of all ways[i - coins[j]] for all j from 1 to the number of coins.
var change = function(amount, coins) {
const ways = Array(amount + 1);
ways[0] = 1;
for(const coin of coins){
for(let i = coin; i <= amount; i++){
ways[i] = (ways[i] ?? 0) + ways[i - coin] ?? 0;
}
}
return ways[amount];
};
console.log(change(5,[1,2,3,4,5]))

Count Down Random Numbers to 0 within given time

I'm creating a countdown, which i need to count down it to 0 but in random numbers.
Ex- countdown from 4 minutes by second by second, but i need to show a value between 300 to 390 countdown to 0 with random numbers within above 4 minutes period.
I created random number count down, but still cannot able to figure out how to target that become 0 within given time.
<script>
var count = 350; //this is a random value between(300-390)
var timer = setInterval(function() {
//this will generate number between 0 to 10 and reduce it from count randimly
count -= Math.floor(Math.random()*9);
//set it to html element
jQuery('#maindvpart').html(count);
//when number become 0
if( count <= 0) {
jQuery('#maindvpart').html(0);
count = 0;
clearInterval(timer);
}
//but i need to run this countdown within 4 minutes
//(so when 0 minutes ends above count should zero, until 0 it should count down from random number)
},1000);
</script>
<div id="maindvpart"> </div>
anyone have idea or example how to do this, thank you
Your "timer" runs each second. When you do "count -= Math.floor(Math.random()*9);", it reduces "count" variable value much faster, so you will always reach "count <= 0" much faster than 4 minutes. If you want to run your timer for 4 minutes, you need to run your timer per second - 240 times, and "display a random number", but do not subtract that random number from count. Does this help?
Editing with an example, hoping it would point you towards your goal:
<script>
var count = 240; //4 minutes
var displayNumber = 350; //or whatever number you want to start with
var timer = setInterval(function() {
//this will generate number between 0 to 10 and reduce it from displayNumber randomly
displayNumber -= Math.floor(Math.random()*9);
count--;
console.log(displayNumber);
// exit if either the display number is <= 0 or the time is up
if( displayNumber <= 0 || count <= 0) {
console.log(0);
displayNumber = 0;
clearInterval(timer);
}
},1000);
</script>
Solution 1:
simply modify the time interval after which the random number is reduced by unit step (ie:1) to indicate the time step necessary for the random number to equal 0 when the time is up . the equation would be :
{delay before subtracting 1 from rand# (in sec) = time elapsed till rand# reaches 0 (in sec)/rand#}
ex:
1) rand# = 300 , needed to count down till reaches 0 in 2 minutes (120sec) , then 300 needs to count down by 1 each 120/300 sec
var count = 300 // your randomly generated number;
var time = 60 //time elapsed before the random number to equal 0;
var timer = setInterval(function() {
count = count -1;
console.log(count);
if( count <= 0) {
count = 0;
clearInterval(timer);
}
},(time/count)*1000);
Solution 2:
modify the unit step by which the random number is decreased every second till it reaches 0 after the specified time is elapsed . the equation would be :
{random # decrement step = rand#/time elapsed till rand# reaches 0 (in sec)}
ex:
1) rand# = 300 , needed to count down till reaches 0 in 1 minute (60sec) , then 300 needs to count down by 300/60 each 1 sec
var count = 300 // your randomly generated number;
var time = 20 //time elapsed before the random number to equal 0;
var decrementStep=count/time;
var timer = setInterval(function() {
count = count - decrementStep;
console.log(count);
if( count <= 0) {
count = 0;
clearInterval(timer);
}
},1000);

I have a field calculating and need to display a minimum if the result is below 60

Sorry this is obviously my first time here, I am just learning how to work in javascript. My question is this: I have some basic calculations determing a price of a service for our non-profit. t is the number of rooms * 0.81. But we have a monthly minimum of $60. So I need to know how I would factor that into the pricing function. I know it goes that "if x < 60, then 60", just not sure how the language would be written. I will include the full js.
var listenerFieldIDs = {"roomCountID":"item4_text_1"}; //Currently the only form we are using for room count has this value set as its ID attribute.
var impactFields = ["item12_text_1","item1_text_1","item16_text_1","item18_text_1","item20_text_1"]; //Field IDs for the form that will be changed constantly.
var estimatedBottleSize = 1.5, occupancyRate = (60 / 100), collectionDuration = 365, soapOuncesRecoverable = 0.63, bottleOuncesRecoverable = 0.47,lbConversion = 0.0626, rate = 0.81;
var $ = function(id){ //Shortcut to save some typing. Instead of having to write out document.getElementById(elementID) every time I need to access an element, I can put $(elementID).property or $(elementID).method() I need more easily.
return document.getElementById(id);
}
var updateFormField = function(id,amount){ //Updates a form field when gives the element ID and the amount.
$(id).value = amount;
}
var updateForm = function(roomCount){
// This is called when all form data needs to be updated. This is generally invoked each time a keystroke in the room count field.
updateFormField(impactFields[0],calculateLbsOfSoap(roomCount).toFixed(2)); //Updating the first form field after calculating the total weight of soap in lbs.
updateFormField(impactFields[1],calculateLbsOfBottles(roomCount).toFixed(2)); //Same thing as above, but bottles/amenities.
updateFormField(impactFields[2],calculateBarsOfSoap(roomCount).toFixed(0)); //Updating the third form field after calculating the total number of distributed units.
updateFormField(impactFields[3],calculateBottles(roomCount).toFixed(0)); //Same as above, but bottles/amenities.
updateFormField(impactFields[4],("$" + calculatePrice(roomCount).toFixed(2))); //Updating price.
}
var listenForNumbers = function(event){ //This function is acting as a handler for when anything is entered into the field.
updateForm($(listenerFieldIDs["roomCountID"]).value);
}
var calculateLbsOfSoap = function (rmCnt){ // Calculate the weight of soap and return the amount.
return checkCount(rmCnt) ? 0 : ((soapOuncesRecoverable * lbConversion) * (rmCnt * occupancyRate) * collectionDuration);
}
var calculateLbsOfBottles = function (rmCnt){ // Calculate the weight of bottled amenities and return the amount.
return checkCount(rmCnt) ? 0 : ((bottleOuncesRecoverable * lbConversion) * (rmCnt * occupancyRate) * collectionDuration);
}
var calculateBarsOfSoap = function(rmCnt){ // Calculate how many bars are distributed if the room count is not 0.
return checkCount(rmCnt) ? 0 : ((calculateLbsOfSoap(rmCnt) * 16) / 3);
}
var calculateBottles = function(rmCnt){ // Calculate how many bottles are distributed if the room count is not 0.
return checkCount(rmCnt) ? 0 : (((calculateLbsOfBottles(rmCnt) * 16) / estimatedBottleSize) * (2 / 3));
}
var calculatePrice = function(rmCnt){
return checkCount(rmCnt) ? 0 : (rmCnt * rate);
}
var checkCount = function(count){ //If the count is 0 or less than 0, the number is useless so just return 0 to prevent odd results.
return (count < 0 || count == 0) ? true : false;
}
var initializeRealTimeCalcToForm = function(){
if(window.attachEvent){
$(listenerFieldIDs["roomCountID"]).attachEvent("onkeydown",listenForNumbers,false);
$(listenerFieldIDs["roomCountID"]).attachEvent("onkeyup",listenForNumbers,false);
$(listenerFieldIDs["roomCountID"]).attachEvent("onkeypress",listenForNumbers,false);
$(listenerFieldIDs["roomCountID"]).attachEvent("onchange",listenForNumbers,false);
} else{
//But if NOT IE... :-D
$(listenerFieldIDs["roomCountID"]).addEventListener("keydown",listenForNumbers,false);
$(listenerFieldIDs["roomCountID"]).addEventListener("keyup",listenForNumbers,false);
$(listenerFieldIDs["roomCountID"]).addEventListener("keypress",listenForNumbers,false);
$(listenerFieldIDs["roomCountID"]).addEventListener("change",listenForNumbers,false);
}
}
window.onload = function(){
initializeRealTimeCalcToForm();
}
If you only want to set a minimum value of 60 to the variable myvar, you can do
myvar=Math.max(60,myvar);
Edit:
Then, if you want the value returned by calculatePrice to be at least 60, use:
var calculatePrice=function(rmCnt){
return Math.max(60,checkCount(rmCnt) ? 0 : (rmCnt * rate));
}
Note 1:
Do you know that you can declare functions like this?
function calculatePrice(rmCnt){
return Math.max(60,checkCount(rmCnt) ? 0 : (rmCnt * rate));
}
It's shorter and this way you can call the function before declaring it!
Note 2:
If you want that value to be at least 60, I don't understand the following code:
checkCount(rmCnt) ? 0
Why 0?

Calculating tier price

This is the example data:
100 items or less = $20
200 items or less = $15
500 items or less = $10
Example scenario:
user inputs 150 items -> price is $15 per item
And this is how far I get:
http://jsfiddle.net/ByPh5/
<script type="text/javascript">
$(function(){
var tier_prices = {
'100':'20',
'200':'15',
'500':'10'
}
var user_input = $('#user_input').val();
var price_output = 0;
/*
calculate
*/
$('#price_output').text(price_output)
})​
</script>
<input type="text" id="user_input" value="150"/>
<p id="price_output"></p>​
any help is much appreciated
(Note: Since you left some ambiguity, I'll assume that 500+ items also cost $20.)
Instead of messing with that data-structure, you can do something simpler. First the code, then the explanation (if the comments aren't enough.)
function determine_price ( qty ) {
var prices = [
20, //0 to 99
20, //100 to 199
15, //200 to 299
15, //300 to 399
15, //400 to 499
10 //500+
];
//divide by the common denominator
//0-99 turn into 0,
//100-199 turns into 1
//200-299 turns into 2
//and so on
qty = Math.floor( qty / 100 );
//check for 600+, which are the same as 500 (last array item)
return prices[ qty ] || prices.pop();
}
100, 200 and 500 have something in common: They're multiples of 100. So we take an array, and treat each element as if it's a range of 100: the first element (0) is 0 to 99 items, second element (1) is 100 to 199 items and so forth. Then, for each input quantity, we divide by that common denominator, to find out in which range it falls, and grab the price corresponding to that quantity.
In the case of ambiguity, which is what happens for 600+ elements (the last element, element #6 is for 500-599), we simply take the last range's price.
No need for loops, just simple math.
First, instead of specifying the max quantity for a price tier, specify the min quantity. And define it as a sorted array so you can iterate through it.
var tier_prices = [
{ minQty: 0, unitPrice: 20 },
{ minQty: 101, unitPrice: 15 },
{ minQty: 201, unitPrice: 10 }
];
Then, loop through the values until you get to a minimum quantity that is greater than the entered quantity:
var qty = +$('#user_input').val();
var price;
for (var i = 0; i < tier_prices.length && qty >= tier_prices[i].minQty; i++) {
price = tier_prices[i].unitPrice;
}
$('#price_output').text(price * qty);
http://jsfiddle.net/gilly3/ByPh5/3/
Objects are nice but a bit annoying since you're not guaranteed to go through the values in order.
http://jsfiddle.net/radu/6MNuG/
$(function() {
var tier_prices = {
'100': '20',
'200': '15',
'500': '10'
};
$('#user_input').change(function() {
var num = parseInt($(this).val(), 10),
price = 0,
prevTier = 0,
maxTier = 0;
for (var tier in tier_prices) {
if (tier_prices.hasOwnProperty(tier) && num <= tier) {
if (tier < prevTier || prevTier == 0) {
price = tier_prices[tier];
prevTier = tier;
}
}
if (tier > maxTier) maxTier = tier;
}
if (num > maxTier) price = tier_prices[maxTier];
$('#price_output').text(price * num);
});
})​;​
Example with a multidimensional array: http://jsfiddle.net/radu/6MNuG/
$(function() {
var tier_prices = [
[100, 20],
[200, 15],
[500, 10]
];
$('#user_input').change(function() {
var num = parseInt($(this).val(), 10),
price = 0,
n = tier_prices.length - 1;
if (num > tier_prices[n][0]) {
price = tier_prices[n][1];
} else {
for (var i = 0; i <= n; i++) {
if (num <= tier_prices[i][0]) {
price = tier_prices[i][1];
break;
}
}
}
$('#price_output').text(price * num);
});
});​
Try:
var tier_prices = {
'100': '20',
'200': '15',
'500': '10'
}
var price_output = 0;
var multiplier = 1;
$('#user_input').change(function() {
var user_input = parseInt($('#user_input').val(),10);
for (tier in tier_prices) {
if (user_input <= tier) {
multiplier = tier_prices[tier];
break;
}
}
$('#price_output').text(user_input * multiplier);
});​
jsFiddle example
UPDATE
Here's an example forgoing the object you had with a simple switch/case since the idea of the object isn't very popular or functional. Note that I added a case for quantities greater than 500:
$('#user_input').change(function() {
var user_input = parseInt($('#user_input').val(), 10);
switch (true) {
case user_input >= 0 && user_input <= 100:
$('#price_output').text(user_input * 20);
break;
case user_input > 100 && user_input <= 200:
$('#price_output').text(user_input * 15);
break;
case user_input > 200 && user_input <= 500:
$('#price_output').text(user_input * 10);
break;
case user_input > 500:
$('#price_output').text(user_input * 5);
}
});​
jsFiddle example
Was looking for a similar thing and decided to do it slightly different, ran it in js fiddle and it seems to work pretty well. As gilly3 pointed out you probably don't want an upper limit, so you might want to do '1 or more, 100 or more...500 or more'. The vars and div names I used were different but you can see what I'm trying to do and adapt it to your needs:
JSFiddle: https://jsfiddle.net/vx4k2vdh/5/
(function() {
const tiers = {
0: 20,
100: 15,
200: 10,
500: 5
}
/**
* Take qty and return the first appropriate
* tier that it encounters, break when
* tier has been identified so you don't
* waste time iterating if u've already found tier
**/
function calculatePriceTier(qty) {
var selectedTier;
for (var tier in tiers) {
if (tiers.hasOwnProperty(tier)) {
if (qty < tier) break;
selectedTier = tier;
}
}
return selectedTier;
}
$(function() {
/**
* Every time a new number is selected
* run calculations and grab tier, total
**/
$('#items').on('input', 'input', function() {
var qty = +$(this).val(),
tier = calculatePriceTier(qty),
total = qty * tiers[tier];
$('#total-price span').text(total);
});
});
})();
What is described in the OP's request is volume pricing.
All the examples given here are for volume pricing not tier pricing.
Tire pricing example in ruby
https://repl.it/repls/IndigoRightDisks
def cost(qty)
tier = {
10 => 100,
50 => 97,
100 =>82,
200 =>71,
300 =>66,
400 =>64,
500 =>27,
1000 =>12
}
cs = []
for cnt in 1..qty
d = tier.keys.find{|x| cnt <= x ?cnt <= x : tier.keys.last == x }
cs << tier[d]
end
return cs.reduce{|y,x| y+x};
end

Categories