JavaScript Cash Register Challenge -- Not sure why this error persists

This isn’t a fully completed project, but I do have a solid idea of what I have left to do. The problem I’m facing is how to overcome a TypeError that occurs in the project.

My code is below:

function checkCashRegister(price, cash, cid) {

  // this will NOT change
  const DENOMINATIONS = [
    ["PENNY", 1],
    ["NICKEL", 5],
    ["DIME", 10],
    ["QUARTER", 25],
    ["ONE", 100],
    ["FIVE", 500],
    ["TEN", 1000],
    ["TWENTY", 2000],
    ["ONE HUNDRED", 1000],
  ]
  
  let priceInPennies = price * 100;
  let cashInPennies = cash * 100;
  let changeInPennies = Math.floor(cashInPennies - priceInPennies);

  // This sets the cash in drawer amounts equal to values in pennies
  let cidValues = cid
  for (let i = 0; i < cidValues.length; i++) {
    cidValues[i][1] *= 100
    // console.log(cidValues[i][1])
  }

  //console.log(cidValues[4])

  let change = []
  while (changeInPennies > 0) {
    for (let j = cidValues.length - 1; j >= 0; j--) {
      console.log(cidValues[j][1])
      let placeholder = [cidValues[j][0], 0]
      // "while there is change in the drawer at the given currency and while a unit of the denomination can be subtracted from the change due..."
      while ((cidValues[j][1] > 0) && (changeInPennies - DENOMINATIONS[j][1])) {
        // subtract a unit of denomination from the change due
        changeInPennies -= DENOMINATIONS[j][1]
        // subtract a unit of denominations from the cash in drawer (values)
        cidValues -= DENOMINATIONS[j][1]
        // add a unit of denomination to the placeholder
        placeholder[1] += DENOMINATIONS[j][1]
      }
      if (placeholder[1] > 0) {
        change.append(placeholder)
      }
    }
  }
  
}

checkCashRegister(19.5, 20, [["PENNY", 0.01], ["NICKEL", 0], ["DIME", 0], ["QUARTER", 0], ["ONE", 0], ["FIVE", 0], ["TEN", 0], ["TWENTY", 0], ["ONE HUNDRED", 0]]);

and the error I get is:

TypeError: Cannot read property '1' of undefined

When I copy/paste the code into Visual Studio Code, the editor specifies that the TypeError occurs on this line, specifically the cidValues[j][1] part:

while ((cidValues[j][1] > 0) && (changeInPennies - DENOMINATIONS[j][1])) {

However, the console.log(cidValues[j][1]) on the line immediately above it works fine. As it stands in the FCC editor, the code currently prints out the following:

0
0
0
0
0
0
0
0
1
TypeError: Cannot read property '1' of undefined

I don’t necessarily need help solving this challenge (yet). I just have no clue why I’m getting this TypeError. Any help would be greatly appreciated.

I suspect that something weird is happening by trying to modify cidValues here.

        cidValues -= DENOMINATIONS[j][1]
1 Like

That was it!! Wow, and you were quick. Thank you so, so much. I was looking for the error in the wrong place. I changed the line in question to:

cidValues[j][1] -= DENOMINATIONS[j][1]

and the error disappeared. Now to fix the other errors, haha. Thanks again.

This probably doesn’t do what you think it does.

Hmm… my intention in that line is to store the value of cid into a new variable that I can take actions on without mutating cid. Doing console.log(cid) and console.log(cidValues) produces the same results. That said, I could be missing something.

That’s what I suspected. When you have an array or object, that won’t create a copy:

// Try to copy an array
const myArr = [1, 2, 3];
const myOtherArr = myArr;
console.log("Before:");
console.log(myArr);
console.log(myOtherArr);

// Change 'copy'
myOtherArr[0] = 42;
console.log("\nAfter:");
console.log(myArr);
console.log(myOtherArr);

Ah, I see that now. Thank you for catching that. It looks like one way to prevent that problem is to do something like:

let cidValues = [...cid]
1 Like

But, you have an array of arrays. Each array inside of your array has the same problem.

1 Like

Good catch again, thank you. Hmm… I suppose I could apply the same solution above to the nested array as well, but I might also try mutating the original cid value to do away with that issue entirely. Something like this:

const cid = [["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.1], ["QUARTER", 4.25], ["ONE", 90], ["FIVE", 55], ["TEN", 20], ["TWENTY", 60], ["ONE HUNDRED", 100]];
for (let i = 0; i < cid.length; i++) {
  cid[i] = [cid[i][0], Math.round(cid[i][1] * 100)]
}
console.log(cid) 

which prints out:

[
  [ 'PENNY', 101 ],
  [ 'NICKEL', 205 ],
  [ 'DIME', 310 ],
  [ 'QUARTER', 425 ],
  [ 'ONE', 9000 ],
  [ 'FIVE', 5500 ],
  [ 'TEN', 2000 ],
  [ 'TWENTY', 6000 ],
  [ 'ONE HUNDRED', 10000 ]
]

Not sure if it’s best practice, but I’ll try tinkering with it that way, since the only purpose of cidValues is to have the penny values of each denomination in cid.

I wouldn’t mutate the input, personally. With some small changes, the loop to modify cid can also just make a copy of it.

Thanks for the insight – I’m sure it could be cleaner (I’m already spotting places where it could be cleaned up), but I got all the tests passing (!!) with this:

function checkCashRegister(price, cash, cid) {

  // this will NOT change
  const DENOMINATIONS = [
    ["PENNY", 1],
    ["NICKEL", 5],
    ["DIME", 10],
    ["QUARTER", 25],
    ["ONE", 100],
    ["FIVE", 500],
    ["TEN", 1000],
    ["TWENTY", 2000],
    ["ONE HUNDRED", 10000],
  ]

  let priceInPennies = price * 100;
  let cashInPennies = cash * 100;
  let changeInPennies = Math.floor(cashInPennies - priceInPennies);

  // thanks to https://www.freecodecamp.org/news/how-to-clone-an-array-in-javascript-1d3183468f6a/
  let cidValueInPennies = JSON.parse(JSON.stringify(cid))

  // This sets the cash in drawer amounts equal to values in pennies
  for (let i = 0; i < cid.length; i++) {
    cidValueInPennies[i][1] = Math.round(cid[i][1] * 100)
  }

  let cidSum = 0
  for (let h = 0; h < cidValueInPennies.length; h++) {
    cidSum += cidValueInPennies[h][1]
  }

  if (cidSum == changeInPennies) {
    return {
      status: "CLOSED",
      change: cid
    }
  }  

  let change = []
  while (changeInPennies > 0) {
    for (let j = cidValueInPennies.length - 1; j >= 0; j--) {
      let placeholder = [cidValueInPennies[j][0], 0]
      // "while there is change in the drawer at the given currency and while a unit of the denomination can be subtracted from the change due..."
      while ((cidValueInPennies[j][1] > 0) && ((changeInPennies - DENOMINATIONS[j][1]) >= 0)) {
        // subtract a unit of denomination from the change due
        changeInPennies -= DENOMINATIONS[j][1]
        // subtract a unit of denominations from the cash in drawer (values)
        cidValueInPennies[j][1] -= DENOMINATIONS[j][1]
        // add a unit of denomination to the placeholder
        placeholder[1] += DENOMINATIONS[j][1]
      }
      if (placeholder[1] > 0) {
        change.push(placeholder)
      }
    }
    // Cannot return exact change, or not enough cash in drawer
    if (changeInPennies > 0) {
      return {
        status: "INSUFFICIENT_FUNDS",
        change: []
      }
    }
  }
  // This returns the values in pennies back to the original amounts
  let finalChange = JSON.parse(JSON.stringify(change))
  for (let m = 0; m < finalChange.length; m++) {
    finalChange[m][1] = (finalChange[m][1] / 100)
  }
  return({
      status: "OPEN",
      change: finalChange
    })
}

Whew, learned a lot through this problem, that’s for sure.

1 Like

Nice work getting it running!


You can combine these two actually:

  // Copy drawer to cents
  let drawer = cid
    .map(denom => [denom[0], Math.round(denom[1] * 100)]);

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.