Exact change strange behaviour in loops

HI folks, been working on this a while (on and off), hoping that the answer will come to me. If I use this code, the amount of change is right, but the following reduce method (which I found on StackOverflow), doesn’t add them in the correct way.

The weird thing is, when I test the reduce method as a standalone function with the same output from the checkCashRegister function, it works. I’m stumped. Anyone have any ideas? The standalone function is below for reference. there is probably a simple answer to this . . . .

function checkCashRegister(price, cash, cid) {
    var change = cash - price;
    var cashTotal = 0;
    var coinsReturned = [];
    var denom = [
        ['ONE HUNDRED', 100],
        ['TWENTY', 20],
        ['TEN', 10],
        ['FIVE', 5],
        ['ONE', 1],
        ['QUARTER', 0.25],
        ['DIME', 0.1],
        ['NICKEL', 0.05],
        ['PENNY', 0.01]
    ];

    var till = [];
    var denomStart;
    cid.forEach(function(item) {
        till.push(item[1].toFixed(2));
    });
    till.reverse();
    (function() {

        for (var i = 0; i < till.length; i++) {
            cashTotal += till[i][1];
        }
        return cashTotal = cashTotal;
    })();

   if (change > cashTotal) {
        return 'Insufficient funds';
      
    } else if (change === cashTotal) {
        return 'Closed';
    } else {
      
        for (var x = 0; x < denom.length; x++) {
            if (change === 0) {
                break;
            } else if (change < denom[x][1]) {
                continue;
            } else if (change > denom[x][1]) {
                change -= denom[x][1];
                till[x] -= denom[x][1];
                coinsReturned.push(denom[x]);
                if (till[x] === 0) {
                    continue;
                } else {
                    x--;
                }
            }
        }

         //reduce method
        var duplicateIndex = {};
        var outputArr = [];
        for (var i = 0; i < coinsReturned.length; i++) {
            var item = coinsReturned[i];
            //var item = holdingCoin[i][0] + "," + holdingCoin[i][1].toFixed(2); 
            var collisionIndex = duplicateIndex[item[0]];
            if (collisionIndex > -1) {
                outputArr[collisionIndex][1] += item[1];
            } else {
                outputArr.push(item).toFixed(2);
                duplicateIndex[item[0]] = outputArr.length - 1;
            }
        }
        return outputArr;
    }
}

checkCashRegister(3.26, 100.00, [
    ["PENNY", 1.01],
    ["NICKEL", 2.05],
    ["DIME", 3.10],
    ["QUARTER", 4.25],
    ["ONE", 90.00],
    ["FIVE", 55.00],
    ["TEN", 20.00],
    ["TWENTY", 60.00],
    ["ONE HUNDRED", 100.00]
]);
//end of first function

//standalone test:

var holdingCoin = [
    ["TWENTY", 20],
    ["TWENTY", 20],
    ["TWENTY", 20],
    ["TEN", 10],
    ["TEN", 10],
    ["FIVE", 5],
    ["FIVE", 5],
    ["FIVE", 5],
    ["ONE", 1],
    ["QUARTER", 0.25],
    ["QUARTER", 0.25],
    ["DIME", 0.1],
    ["DIME", 0.1],
    ["PENNY", 0.01],
    ["PENNY", 0.01],
    ["PENNY", 0.01]
];

var findDuplicatesAndSum = function(inptArr) {
    var duplicateIndex = {};
    var outputArr = [];
    for (var i = 0; i < inptArr.length; i++) {
        var item = inptArr[i];
        //    var item = inptArr[i][0] + "," + inptArr[i][1].toFixed(2); 

        //outputArr.push(item);
        var collisionIndex = duplicateIndex[item[0]];
        if (collisionIndex > -1) {
            outputArr[collisionIndex][1] += item[1];
        } else {
            outputArr.push(item).toFixed(2);
            duplicateIndex[item[0]] = outputArr.length - 1;
        }
    }
    return outputArr;
};
findDuplicatesAndSum(holdingCoin);


Hey @aah101,
I didn’t really understand what your problem is. I have run your code with the example test you gave and it seems to merge similar coins together into one field.

What I did notice is the fact that you have an anonymous function inside your function, which is not a good idea.

    till.reverse();
    (function() {

        for (var i = 0; i < till.length; i++) {
            cashTotal += till[i][1];
        }
        return cashTotal = cashTotal;
    })();

I would output that code into a separate function and call it.

Hey Tomer, thanks for getting back, first time on here and realised after posting that I didn’t make the problem clear enough.

If I run the reduce method inside the full function, I get this:

[“TWENTY”, 80],[“TEN”, 20], [“FIVE”, 20], [“ONE”, 1], [“QUARTER”, 0.5],[“DIME”, 0.2], [“PENNY”, 0.04]
which has reduced the output from the first function:

[“TWENTY”, 20],[“TWENTY”, 20],[“TWENTY”, 20],[“TEN”, 10],[“TEN”, 10],[“FIVE”, 5],[“FIVE”, 5],[“FIVE”, 5],[“ONE”, 1],[“QUARTER”, 0.25],[“QUARTER”, 0.25],[“DIME”, 0.1],[“DIME”, 0.1],[“PENNY”, 0.01],[“PENNY”, 0.01],[“PENNY”, 0.01]

But If I run the reduce method on its own using the same output as a parameter, I get this:

[“TWENTY”, 60],[“TEN”, 20],[“FIVE”, 15],[“ONE”, 1],[“QUARTER”, 0.5],[“DIME”, 0.2],[“PENNY”, 0.03]

I’ve run the debugger on it, and can see that in the first example, the reduce method is changing each instance of, say 20, in the coinsReturned array, in the latter, it changes only the first instance.

Anyway, I’m gonna change that anonymous function first and see if that changes anything. thanks for the advice.

Hi Randell, thanks for doing that. It’s a great tip for next time I get stuck.

I did sort of arrive at that conclusion about those two lines:

var item = coinsReturned[i];
 outputArr[collisionIndex][1] += item[1];

… through watching what happens to each array at each stage of the loop in the debugger. The ‘weird’ thing is that the exact same output used as a parameter in a standalone function works.

I even tried declaring all the variables globally, including the function to replicate it.

So maybe I’m gonna try to find another way of reducing the duplicates in the array and will come back when done. Appreciate very much the help.