Least amount of coins to use given an amount - javascript

I'm trying to create a function in javascript/jquery to work out what the minimum number of coins it would take to add up to a total inputed amount.
So I have an object array of the coins:
var coins = [
{
pennies: 200,
print: '£2'
},
{
pennies: 100,
print: '£1'
},
{
pennies: 50,
print: '50p'
},
{
pennies: 20,
print: '20p'},
{
pennies: 10,
print: '10p'
},
{
pennies: 5,
print: '5p'},
{
pennies: 2,
print: '2p'
},
{
pennies: 1,
print: '1p'
}
];
var $input = $('input');
$input.keypress(function(e) {
if (e.which == 13) {
// do something
}
});
And an input field in my HTML.
So if someone enters 123p I would like the form to return 1 x £1, 1 x 20p, 1 x 2p and 1 x 1p.
I'm struggling to figure out where to start. If anyone could help it would be much appreciated.
Thanks

It sounds like you just need to iterate over the coins array, starting from the highest denomination:
const coins=[{pennies:200,print:'£2'},{pennies:100,print:'£1'},{pennies:50,print:'50p'},{pennies:20,print:'20p'},{pennies:10,print:'10p'},{pennies:5,print:'5p'},{pennies:2,print:'2p'},{pennies:1,print:'1p'}];
const getCoins = penniesToGo => coins.reduce((coinCountStr, { pennies, print }) => {
const numCoins = Math.floor(penniesToGo / pennies);
if (numCoins < 1) return coinCountStr;
penniesToGo -= numCoins * pennies;
const thisCoinStr = `${numCoins}x ${print}`;
return coinCountStr ? coinCountStr + ', ' + thisCoinStr : thisCoinStr;
}, '');
console.log(getCoins(201));
console.log(getCoins(333));
console.log(getCoins(6));

Related

How to use the sum of values in an array inside FOR loop Node Js

My problem is that I want to get the total sum of SplitValue that has the SplitType of RATIO and use it inside the FOR loop to calculate the ratio of split. i.e. 3 + 2 = 5.
The comments I made in each line of my code below explain my troubles, I'm getting a loop of 3 and 5 instead of just 5. Thanks
var details = {
"Amount": 1396.8000000000002,
"SplitInfo": [{
"SplitType": "RATIO",
"SplitValue": 3
},
{
"SplitType": "RATIO",
"SplitValue": 2
}
]
};
var conRatioSumArr = 0;
var balance = details.Amount;
for (var i = 0; i < details.SplitInfo.length; i++) {
// I want to Get the total sum of SplitValue that has the SplitType of RATIO
// 3 + 2 = 5
// Here is what I've tried
splitTypeArr = details.SplitInfo[i].SplitType;
splitValueArr = details.SplitInfo[i].SplitValue;
if (splitTypeArr === "RATIO") {
conRatioSumArr += splitValueArr;
console.log(conRatioSumArr); // This gives me a loop of 3 & 5. I only need the total value which is 5 instead of both 3 and 5. Note that if I put this outside the for loop, I get only the total which is 5, but I want to use the sum inside of this for loop not outside the for loop to enable me calculate the ratio below.
splitAmount = (balance * (splitValueArr / 5)); // The total above is expected to replace the 5 here, but I'm getting a loop of 3 & 5 instead.
// Like this
// splitAmount = (balance * (splitValueArr / conRatioSumArr));
// splitAmount is expected to give: 838.08 and 558.7200000000001 split respectively
console.log(splitAmount);
}
}
I think you are making it too complicated.
All you need to do is get the total amount of parts in the ratio, and then do the (simple) math.
var details = {
amount: 1396.8000000000002,
splitInfo: [
{
type: "RATIO",
value: 3,
},
{
type: "RATIO",
value: 2,
},
],
};
let totalParts = 0;
for (const split of details.splitInfo) {
if (split.type == "RATIO") totalParts += split.value;
}
for (const split of details.splitInfo) {
if (split.type == "RATIO") {
let amountForSplit = details.amount * (split.value / totalParts);
console.log(amountForSplit);
}
}
This code is simple to understand and modify I hope to your liking. Using the array method reduce.
var details = {
"Amount": 1396.8000000000002,
"SplitInfo": [{
"SplitType": "RATIO",
"SplitValue": 3
},
{
"SplitType": "RATIO",
"SplitValue": 2
}
]
};
var result = details.SplitInfo.reduce(function(agg, item) {
if (item.SplitType == "RATIO") {
agg.sum = (agg.sum || 0) + item.SplitValue
agg.count = (agg.count || 0) + 1
}
return agg;
}, {})
console.log(result)
console.log("average is " + result.sum / result.count)

How to check to which Tier our Number belongs to?

So we have that :
{TierLowerBound : 2,
TierUpperBound : 5,
TierName : 'Tier 1',
TierDiscount : 0.15},
{TierLowerBound : 6,
TierUpperBound : 10,
TierName : 'Tier 2',
TierDiscount : 0.40}
And given number for example let i=5;
What can be the best way to find out to which of the tiers our number i belongs to?
I created simple function isBetween, some objects etc. but I am asking, because there are maybe some great ways in JS to deal with that kind of situation?
I'm using foreach loop to check every tier, so it's not as efficient as switch, but switch relays on fixed values, so it would be hard to evalute for instance this situation :
lowerBound = 5;
upperBound = 10;
number = 7;
Looking forward for an answer:)
ANSWER
getDiscount : function(number){
let foundTier = tier.tiersArray.filter(function(object){
let isBetween = number >= object.TierLowerBound &&
( number <= object.TierUpperBound || object.TierUpperBound ==
'noLimit')
return isBetween;
}).values().next().value;
return foundTier ? foundTier.TierDiscount : 0;
}
You can use filter:
const yourArrayOfObjects = [
{
TierLowerBound: 2,
TierUpperBound: 5,
TierName: 'Tier 1',
TierDiscount: 0.15
},
{
TierLowerBound : 6,
TierUpperBound: 10,
TierName: 'Tier 2',
TierDiscount: 0.40
}
];
const returnObjectsWhereNumberFitsInBounds = n => {
return yourArrayOfObjects.filter(element => element.TierLowerBound < n && element.TierUpperBound > n)
}
const magicNumberToTest = 4;
console.log(returnObjectsWhereNumberFitsInBounds(magicNumberToTest));
Assuming that you have an array of objects with tier information, here is an approach:
const tiers = [{
TierLowerBound: 2,
TierUpperBound: 5,
TierName: 'Tier 1',
TierDiscount: 0.15
},
{
TierLowerBound: 6,
TierUpperBound: 10,
TierName: 'Tier 2',
TierDiscount: 0.40
}
]
function isBetween(numberGiven) {
let categoryFound = {}
tiers.forEach(function(arrayItem) {
if (numberGiven >= arrayItem.TierLowerBound && numberGiven <= arrayItem.TierUpperBound) {
console.log("The number requested, " + numberGiven + " is in " + arrayItem.TierName + " category!");
categoryFound = arrayItem;
}
});
return categoryFound;
}
isBetween(3);
isBetween(6);
isBetween(9);
// if you want to use the category in another place, call it like this:
const objInRange = isBetween(7);
console.log("objInRange: " + JSON.stringify(objInRange, null, 2));

Weighted Average with ElasticSearch

I'm new to ElasticSearch and i'm trying to make an weighted average in my index.
My data looks like this:
data = [{"id": 344,"q28": 1},{"id": 344,"q28": 1},{"id": 344,"q28": 2}, ...]
"q28": can be equal to 1,2,3 or 4
Example in JavaScript:
var data = [{"id": 344,"q28": 1},{"id": 344,"q28": 1},{"id": 344,"q28": 2}]
function calcWeightAverage(res) {
var score = 0
for (var i in res) {
if (res[i].q28 == 1)
score += 100
else if (res[i].q28 == 2)
score += 50
else if (res[i].q28 == 3)
score += 25
else if (res[i].q28 == 4)
score += 0
}
return score / res.length
}
console.log(calcWeightAverage(data)) // output 83.333...
Can you help me with to find a query that would calculate the weighted average of q28 directly in ElasticSearch ?
Thank you !
UPDATE 1
I'm close, see: "https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-scripting.html"
To test it, i created a file in config/scripts/my_script.groovy
1 + my_var
Then you have to restart ElasticSearch and make this query:
GET /_search
{
"script_fields": {
"my_field": {
"script": {
"file": "my_script",
"params": {
"my_var": 2
}
}
}
}
}
It's working, now i have to work on the script.
How can i loop in all my data to do something like my javascript function ?
Just to help you with a shorter Javascript part for the average.
function calcWeightAverage(res) {
return res.reduce(function (r, a) {
return r + ({ 1: 100, 2: 50, 3: 25, 4: 0 }[a.q28] || 0);
}, 0) / res.length;
}
var data = [{ id: 344, q28: 1 }, { id: 344, q28: 1 }, { id: 344, q28: 2 }];
console.log(calcWeightAverage(data));

Find nearest next even 100

In javascript what's the simplest way to find the next even 100 ("even 100" = 200, 400, etc.) that's closest to the given number. For ex: 1723 should return 1800, 1402 should return 1600, 21 should return 200, 17659 should return 17800 etc. I have the following that finds the nearest 100 next to the given_num but not the even 100
(parseInt(((given_num + 99) / 100 )) * 100 )
I can think of one way of getting the number without zeroes and checking if its odd/even to figure out next even number if its odd.But more curious to see if there's some simple/elegant way.
Based on bmb's comment, it sounds like you want granularity of 200, not 100. If so:
Divide by 200, round up, multiply by 200:
var tests = [
{value: 1723, expect: 1800},
{value: 1402, expect: 1600},
{value: 21, expect: 200},
{value: 17659, expect: 17800}
];
tests.forEach(test);
function test(entry) {
var result = Math.ceil(entry.value / 200) * 200;
console.log({
value: entry.value,
expect: entry.expect,
result: result
});
}
If you really want to work by rounding up to the "next 100," then the result for 1723 must be 1900 if the result for 1402 is 1600, and you do it by dividing by 100, rounding up, multplying by 100, and adding 100 (or dividing by 100, rounding up, adding 1, and multiplying by 100, which is the same thing):
var tests = [
{value: 1723, expect: 1800},
{value: 1402, expect: 1600},
{value: 21, expect: 200},
{value: 17659, expect: 17800}
];
tests.forEach(test);
function test(entry) {
var result = Math.ceil(entry.value / 100) * 100 + 100;
console.log({
value: entry.value,
expect: entry.expect,
result: result
});
}
Call recursively if not even, add 1 to go the next 100 etc
function closestEven(n) {
var x = Math.ceil(n / 100 ), y = x * 100;
return x % 2 === 0 ? y : closestEven(y+1);
}
console.log( closestEven(1723) ); // 1800
console.log( closestEven(1402) ); // 1600
console.log( closestEven(21) ); // 200
console.log( closestEven(17659)); // 17800
Try this:
var given_num = 1723;
var result = (given_num) + (100 - ((given_num + 100) % 100));
alert(result);

JavaScript array find fitting range

I have the following array with two objects:
var myArr = [{
id: 3,
licences: 100
new_value_pr_licence: 40
}, {
id: 4,
licences: 200
new_value_pr_licence: 25
}]
A user wish to buy 150 licences. This means that they fall into the category 100 because they are above 100 licences but below 200 which means they pay $40 per licence.
Note that the array object values varies.
Order your plans by the price per licence:
myArr.sort(function (a, b) {
return a.new_value_pr_licence - b.new_value_pr_licence;
})
then starting from the start of the array, take as many of that plan as you can without going over the number the user wants to buy:
var numUserWants = 150;
var purchases = {};
var cheapestAvailableProduct = myArr.shift();
while (numUserWants > 0 && cheapestAvailableProduct) {
if (numUserWants <= cheapestAvailableProduct.licences) {
purchases[cheapestAvailableProduct.id] = Math.floor(cheapestAvailableProduct.licences / numUserWants);
numUserWants = cheapestAvailableProduct.licences % numUserWants;
}
cheapestAvailableProduct = myArr.shift();
}
At this point, purchases will now be a map of plan id to number:
purchases => {
3: 3
4: 1
}
This doesn't handle the case where over-purchasing is the cheapest option (eg: it's cheaper to buy 160 at 4x40, instead of 150 at 3x40 + 1x25 + 1x5), but it's probably a good start for you to tweaking.
Just a simple forEach here. Take the number requested, begin calculating/mutating total based on option limits, and once the number requested is less than the option limit you have your final total, which wont be mutated any longer and returned from the function.
function calculateDiscountedTotal(numberRequested, myArr){
var total;
// loop, compare, calculate
myArr.forEach(function(option) {
if(numberRequested >= option.licenses){
total = numberRequested * option.new_value_pr_licence
}
}
if(total != undefined){
return total;
} else {
// user never had enough for initial discount
return "no discount price";
}
}
Sort the array first in terms of number of licenses and then get the object in which number of licenses is less than number of licenses to be bought (just less than the next item in the array which is greater than number of licenses to be bought)
var myArr = [
{
id: 3,
licences: 100
new_value_pr_licence: 40,
},
{
id: 4,
licences: 200,
new_value_pr_licence: 25
},
];
var numOfLic = 150;
myArr.sort( function(a,b){ return a.licences - b.licences } );
var selectedObj = myArr.reduce( function(prev,current){
if ( current.licences > numOfLic )
{
return prev;
}
});
console.log ( "pricing should be " + ( selectedObj.new_value_pr_licence * numOfLic ) );

Categories

Resources