首页 > 解决方案 > How do I increment an array value up to another array value in Javascript?

问题描述

//value of currency denominations
    var currencyTable = [100, 20, 10, 5, 1, 0.25, 0.1, 0.05, 0.01];

//total cash at each currencyTable denomination in the cash register 
    var cashInDrawer = [100, 60, 20, 55, 90, 4.25, 3.1, 2.05, 1.01];

//total change due
    var changeDue = 96.74;

My goal is to return the correct change from the cash available from the greatest cash denomination to the lowest.

I can't figure out how to increment a value in currencyTable up to the available amount in cashInDrawer while changeDue >= currencyTable[i].

I've managed so far:

var total = [];
  for (let i = 0; i < currencyTable.length; i++){
  while (changeDue >= currencyTable[i]){
    total.push(currencyTable[i])
    changeDue-=currencyTable[i];
  }
 }return total;

but this only returns:

[20, 20, 20, 20, 10, 5, 1, 0.25, 0.25, 0.1, 0.1, 0.01, 0.01, 0.01]

where I want to return:

[60, 20, 15, 1, 0.5, 0.2, 0.04]

Somewhere in the loop I realize changeDue is being changed into a repeating decimal but I found a temporary workaround using .toFixed().

标签: javascript

解决方案


你完全在正确的道路上。但是,不是push每次都在内部循环中调用,而是需要在循环时添加上一次推送的数量。可能最简单的方法是添加一个变量,然后在最后推送。当您添加到`total cashInDrawer.cashInDrawer

这里有一个固有的问题:您使用 JavaScript 的数字类型来处理金钱。但是 JavaScript 的数字类型不适合处理金钱,IEEE-754 二进制浮点值在十进制领域存在臭名昭著的不精确问题,例如著名的:

console.log(0.1 + 0.2); // 0.30000000000000004

这就是这个问题。如果我们只是应用上面的逻辑修复,我们会得到(见***行):

//value of currency denominations
var currencyTable = [100, 20, 10, 5, 1, 0.25, 0.1, 0.05, 0.01];

//total cash at each currencyTable denomination in the cash register 
var cashInDrawer = [100, 60, 20, 55, 90, 4.25, 3.1, 2.05, 1.01];

//total change due
var changeDue = 96.74;

var total = [];
for (let i = 0; i < currencyTable.length; i++){
    let amount = 0;                                                 // ***
    while (changeDue >= currencyTable[i] && cashInDrawer[i] > 0) {  // ***
        amount += currencyTable[i];                                 // ***
        changeDue -= currencyTable[i];
        cashInDrawer[i] -= currencyTable[i];                        // ***
    }
    // I assume you want to push the amount even if it's 0
    total.push(amount);                                             // ***
}
//return total;
console.log(total);

请注意,最后一个条目是0.03,不是0.04。那是因为changeDue随着我们的进行变得越来越不精确,如果我们记录它,我们可以看到:

//value of currency denominations
var currencyTable = [100, 20, 10, 5, 1, 0.25, 0.1, 0.05, 0.01];

//total cash at each currencyTable denomination in the cash register 
var cashInDrawer = [100, 60, 20, 55, 90, 4.25, 3.1, 2.05, 1.01];

//total change due
var changeDue = 96.74;

var total = [];
for (let i = 0; i < currencyTable.length; i++){
    let amount = 0;                                                 // ***
    while (changeDue >= currencyTable[i] && cashInDrawer[i] > 0) {  // ***
        amount += currencyTable[i];                                 // ***
        changeDue -= currencyTable[i];
        cashInDrawer[i] -= currencyTable[i];                        // ***
        console.log(changeDue);
    }
    // I assume you want to push the amount even if it's 0
    total.push(amount);                                             // ***
}
//return total;
console.log(total);

最后,0.009999999999994869不是>= 0.1,所以循环提前结束。

有关解决此问题的各种方法,请参阅此问题的答案

一种常见的解决方案是使用数字* 100并保持舍入。(有时您可能会使用* 10000然后四舍五入到小数点后两位等。)这是总体思路,必要时进行调整:

//value of currency denominations
var currencyTable = [100, 20, 10, 5, 1, 0.25, 0.1, 0.05, 0.01];
currencyTable = currencyTable.map(entry => Math.round(entry * 100));   // ***

//total cash at each currencyTable denomination in the cash register 
var cashInDrawer = [100, 60, 20, 55, 90, 4.25, 3.1, 2.05, 1.01];
cashInDrawer = cashInDrawer.map(entry => Math.round(entry * 100));     // ***

//total change due
var changeDue = 96.74;

changeDue = Math.round(changeDue * 100);                                // ***
var total = [];
for (let i = 0; i < currencyTable.length; i++){
    let amount = 0;
    while (changeDue >= currencyTable[i] && cashInDrawer[i] > 0) {
        amount += currencyTable[i];
        changeDue -= currencyTable[i];
        cashInDrawer[i] -= currencyTable[i];
    }
    // I assume you want to push the amount even if it's 0
    total.push(amount);
}
//return total;
for (const entry of total) {
    console.log(entry / 100);
}


推荐阅读