Please help me!... I am stuck and I don't understand why

Hi!

After a whole day trying to figure out why decimals in my calcule got insane, now something else it’s happening.

I tryed 3 ways to copy cid : Array.from() , copy = [...cid] , copy = cid.slice() , but every time both cid and copyCID have the same value at the end.

How can I fix it? All tests are passed, but the last one… this one.

Your code so far


function checkCashRegister(price, cash, cid) {

let money = [0.01, 0.05, 0.1, 0.25, 1, 5, 10, 20, 100];
let rest = cash - price;
let change = [];
let copyCID = [...cid];    //trying to copy 'cid'
let sumCID = 0;
let sum = 0;
// console.log(copyCID)    

for (let i = copyCID.length-1; i >= 0; i--) {
  let j = 0;
  sumCID = parseFloat((sumCID + copyCID[i][1]).toFixed(2));   
  while (rest >= money[i] && copyCID[i][1] > 0) {

    rest = parseFloat((rest - money[i]).toFixed(2));
    copyCID[i][1] = parseFloat((copyCID[i][1] - money[i]).toFixed(2));;
    j++;

    if (rest < money[i] || copyCID[i][1] === 0)
      {change.push([copyCID[i][0],money[i]*j])}
  }
}
console.log(cid)                 /*    Both have same answer...
console.log(copyCID)               with [['PENNY', 0], ...]  */  

for (let i = 0; i < change.length; i++) {
  sum = parseFloat((sum + change[i][1]).toFixed(2))
  }

if (sumCID < rest || sum < rest) return {status: "INSUFFICIENT_FUNDS", change: []}
else if (sumCID == sum)  return {status: "CLOSED", change: copyCID}
else return {status: "OPEN", change: change}


}

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

Your browser information:

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36.

Challenge: Cash Register

Link to the challenge:

The way you are copying makes a shallow copy of that array. It makes a separate array (different reference) of to the first level. That means that copyCID is a different array than cid. That would work perfectly if it was an array of primitives. But this is an array of primitives. But it’s not - it’s an array of arrays. So, copyCID[x] is still pointing to the same reference as cid[x]. You either need to find a way to create a deep copy (or deep clone) or find a way to do it without copying the arrays.

Yes, this is a confusing concept. A lot of people get tripped up on this. Even experienced programmers have to stop and think about it sometimes. If this doesn’t help, I can write something better out when I get on a real computer.

1 Like

Yes, it helped! Actualy this is what was in my mind too. But how can I make a deep copy? I tryed with new Array too, but still doesn’t work. Is any posibility to copy without having the same reference?
Maybe with Object.create()

I honestly don’t want to rewrite my code becouse of this…

So i searched for deep copy of an array and i found this:

const nestedCopyWithHack = JSON.parse(JSON.stringify(nestedArray))

Can you explain me please how this combination of JSON.parse and JSON.stringify works?

Yeah, that’s kind of a hacky way of doing it. Why does it work? Well, JSON.stringify takes your data structure and turns it into a JSON object in the form of a string. You can console.log it to see. So, that string is not references to your JS data structure anymore, but a JSON version of that stored in a string. Then JSON.parse accepts that string and tries to turn it into a new JS object and returns it. So, if your object is capable of being turning into JSON, then this will work fine. There are some gotchas - off the top of my head, JSON can’t have circular references and it can’t have certain data types - I think it’s just strings, numbers, booleans, null, arrays, and basic objects (I think no maps or sets or functions). But that isn’t a problem here.

Yeah, I think it’s a little hacky, but for what you need here, it makes sense.

Another way would be to write a custom copy function that knows the shape of your data and intelligently makes copies on each level of array and object.

You could also write a function that recursively goes over the entire data object and makes copies of everything. This would not have to know the shape of your data and would just figure it out. There are already implementations of this, like lodash’s cloneDeep.

Yeah, it’s a weird thing. I almost think I have an advantage because I learned C before I learned JS. In C (and other languages) you have to be very aware of what is a value (primitive) type and what is a reference (an address or pointer). It affects how you pass data to functions and how you copy them. We still have some of those weird side effects in JS, but we don’t have the groundwork of understand that makes that easier to understand - JS handles so much for us behind the scenes - mostly a good thing. But keep at it and you’ll get it. I’m sure there are some good articles and youtube videos explaining the difference between primitive and reference types in JS and how that affects copying/cloning and function parameters.

1 Like

for a bidimensional array you can also do something like:
newArr = arr.map(subArr => subArr.slice())

map returns a new array, you just need to make also a copy of the inner array (which slice does)

it doesn’t work if you don’t know the depth tho, even hacky as it is and with its limitations, the conversation to JSON object works well

1 Like