How to sum up specific array elements?

Hope it helps and you can solve your problem. And overall have fun!

1 Like

Thank you. That really helps.

I see. You were writing multiple posts while I was composing my reply. Which is why we were having two different conversations. I would suggest fixing the program logic first, THEN, after the tests pass, seeing if you can improve the variable naming and use ES6 syntax. Variable names like real2 mean very little to anyone reading it. Something like currencyValues is more explanatory.

The rest of the program is logically sound except this block.

  else if (change < cidtotal) {
    for (var i = real.length-1; i >= 0; i--) {
      while (real[i] < (cid2[i] - real2[i])) {
        real[i] = real[i] + real2[i];
      }
      temp.push(real[i]);
    }

    console.log(temp);
  }

The conditional test is fine, but you’re getting lost because you have the for loop iterating from the end of an array, and it would be better (especially since you are copying the arrays anyway) to work “big money down.” Think about when YOU make change for someone. I don’t know Pakistani currency, but I do know Indian. You don’t start by counting the paise first, you start with the biggest denomination of rupees, then go to smaller currency units until you don’t have to make any more change.
[EDIT]: You may want to use arrayName.reverse() to reverse the elements so they are in big-down order, which will allow you to focus more on iterating from 0-length (which most CPU caches are optimized to do, and don’t do for iterating from length to 0).
[END EDIT]

But, even if that isn’t tripping you up, this while loop doesn’t test the correct condition:

  while (real[i] < (cid2[i] - real2[i]))

You don’t need to know whether the change in the i-th drawer slot is greater than 2 times real[i]. (Since real2[i] === real[i]), you are effectively testing this:

while (2*real[i] < cid2[i])

Instead, you need a way to keep track of how much change you still have to make, and see how much of the change in that change drawer slot can be used to make it:

Thanks for helping me out. But doesn’t my for loop go Big money down? I think it is doing the same thing isn’t it? It’s starting at the last index and going to the 0th index.But yeah, the while loop part does seem incorrect. Let me try to fix it. I will get back to you.

I was saying it could lead to confusion, and realized I didn’t include in my original post how to use arrayName.reverse(), so I said that even if it didn’t confuse you, the while loop is logically broken. See the [EDIT] to my last reply. You need two things to fix your logic, since I fear this is too distributed of a discussion.

  1. A variable to keep track of how much change you still have to give the customer.
  2. Replace the logic INSIDE the for loop (where you now have a while loop) to have it figure out the greatest number of units of currency at slot[i] you can give to fulfill the remaining change requirements held in the variable in point 1 above.

Don’t know how to make logic beyond this:

function checkCashRegister(price, cash, cid) {
  var cidtotal = 0;
  var cid2 = [];
  var temp = [];
  var real2 = [];
  var sum = 0;

 /* var real = [["PENNY", 0.01], ["NICKEL", 0.05], ["DIME", 0.1], ["QUARTER", 0.25], ["ONE", 1], ["FIVE", 5], ["TEN", 10], ["TWENTY", 20], ["ONE HUNDRED", 100]];
 */

  var real = [0.01, 0.05, 0.1, 0.25, 1, 5, 10, 20, 100];

  var change = cash - price;
  console.log(change);

  for (x = 0; x < cid.length; x++) {
    cid2.push(cid[x][1]);
  }
  console.log(cid2);

  cidtotal = cid2.reduce(function(item, total) {
    return item + total;
  }, 0);

  console.log(cidtotal);

  var real2 = real.slice();
  console.log(real2);

  if (change > cidtotal) {
    return {"status" : "INSUFFICIENT_FUNDS", "change" : []};
  }

  else if (change == cidtotal) {
    return {"status" : "CLOSED", "change" : cid};
  }

  else if (change < cidtotal) {
    for (var y = 0; y < real.length; y++) {
        if (real[y] >= change) {
        real.splice(y);
        cid2.splice(y);
      }
    }
    console.log(real);
    for (var i = real.length-1; i >= 0; i--) {
      while (sum <= change) {

      }
    }

    console.log(sum);
  }

}

checkCashRegister(3.26, 100, [["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.1], ["QUARTER", 4.25], ["ONE", 90], ["FIVE", 55], ["TEN", 20], ["TWENTY", 60], ["ONE HUNDRED", 100]]);

what should i put in the while loop. Do i need to add multiples of the values in real array.

The problem with your question is that it maps 1:1 onto “how do I do this project beyond the explicit instructions given?” Answering it more in depth than I already have (look at my last reply) would be a violation of the Academic Honesty Policy on a project that is required for a certification. What I can tell you in addition to what I’ve just said is:

  • You don’t understand arrayName.splice()'s function. Pay special attention the Syntax section in the link.
  • You should be 1 - developing the algorithm THEN 2 - implementing the algorithm. You are literally writing code first. Write it in natural language you can understand (Urdu?) and then translate into code. The best coders sit and think, often with pen and paper, then hit the keyboard. As you get more skilled, the complexity of patterns you can code without thought will increase, but pseudocode on pen and paper, and thinking about edge cases will take you farther than what you are doing now. If you want to , you can write inside the editor in romanized script using comments, then implement those comments. That’s a technique I use often, later modifying the comments so others or “me in the future” can read them instead of the code, and then just map the code onto the natural-language explanations in the comments.

On a personal note, I’ve invested too much energy into this thread, and you have enacted NONE of my suggestions (better variable names, the two in the prior reply, ±aligning all your arrays in big-down order to improve understandability), and continue to ask me to do your thinking for you. Unless you do everything I just re-iterated, I will merely watch but not respond any longer. It is for your own good that I tell you these things. If I can read your code without a headache, then you will understand what you are doing better and be able to figure out where to go from there.

You’re right. I have been extremely dependent on your help and yes, my code isn’t tidy at all. And I have made no efforts to get it tidy either. I just got frustrated because i never got stuck for this long with a challenge. I will try to do it with pen and paper first. Thanks for staying here and helping me out because I didn’t give you any reason to.
Btw, the splice function is working as a intended.

1 Like

I remember watching this interview a while back about work at google, the guy was given a similar challenge but it referred to finding a pair (not a combination) of numbers that would add up to the desired sum. He came up with a few ways to achieve that.

Just posting it in case it’d prove helpful:

1 Like

Hi. I am replying to you because i think I am very close to the solution. This is how my For loop looks like now:

for (var i = real.length-1; i >= 0; i--) {
      divider.unshift(Math.round(cid2[i] / real[i]));
      for (var j = 1; j < divider[i]; j++) {
        while (sum <= change) {
          sum = sum + (real[i] * j);
        }
      }
    }

The problem is, the sum should be equal to 96.74 but it is giving me 96.75. I know there’s a minor mistake somewhere there. Can you help me point it out. Btw the pen and paper method really helped.

I said ALL my suggestions and I meant it. If you ever plan on working with even one coder, asking them to strain to read your code every time is a jerk move. Especially when replacing variable names is as simple as “find/replace all.” I’m glad you’re having a better time with designing your algorithms, but I saw real and the new symbol divider and stopped reading. I might have even forgiven the backwards array iteration which is actually NOT optimized - see point 3 about CPU caching, but you seem to think my time comes without the price of writing BETTER, READABLE code. I’m not being a sadist. I’m trying to teach you. Learn.

This is a shortest path problem. Don’t be afraid to think outside the box.

Thanks. I will get to that as well once I am done with my current code.

I have made the changes that you suggested but I am getting different results now. The sum value should be 96.75 in accordance with previous code but now its 100. I have checked and re-checked the new code. All loops seem to be ok.

function checkCashRegister(price, cash, cid) {
  var cidtotal = 0;
  var cidValues = [];
  var sum = 0;
  var divider = [];

  var currencyValues = [0.01, 0.05, 0.1, 0.25, 1, 5, 10, 20, 100];
  currencyValues.reverse();

  var change = cash - price;
  console.log(change);

  for (var x = 0; x < cid.length; x++) {
    cidValues.push(cid[x][1]);
  }
  cidValues.reverse();

  cidtotal = cidValues.reduce(function(item, total) {
    return item + total;
  }, 0);

  console.log(cidtotal);

  if (change > cidtotal) {
    return {"status" : "INSUFFICIENT_FUNDS", "change" : []};
  }

  else if (change == cidtotal) {
    return {"status" : "CLOSED", "change" : cid};
  }

  else if (change < cidtotal) {
    for (var y = 0; y < currencyValues.length; y++) {
        if (currencyValues[y] >= change) {
        currencyValues.splice(y, 1);
        cidValues.splice(y, 1);
      }
    }
    console.log(currencyValues);
    console.log(cidValues);
    for (var i = 0; i < currencyValues.length; i++) {
      divider.push(Math.round(cidValues[i] / currencyValues[i]));
      //divider is the value of cidValues / currencyValues
      for (var j = 1; j <= divider[i]; j++) {
        while (sum <= change) {
        sum = sum + (currencyValues[i] * j);
        }
      }
    }
    //console.log(divider);
    console.log(divider);
    console.log(sum);
  }

}

checkCashRegister(3.26, 100, [["PENNY", 1.01], ["NICKEL", 2.05], ["DIME", 3.1], ["QUARTER", 4.25], ["ONE", 90], ["FIVE", 55], ["TEN", 20], ["TWENTY", 60], ["ONE HUNDRED", 100]]);

Now I have further improved the code and now I am closer than ever. The sum value equals to 96.73. Here is my updated For loop:

for (var j = 1; j <= divider[i]; j++) {
        while ((sum + (currencyValues[i] * j)) <= change) {
        sum = sum + (currencyValues[i] * j);
        }
      }

You’re making progress! We aren’t scraping for every byte of file size anymore, and with minifiers, the length of variable names doesn’t matter. In fact, well-named variables can decrease the need to comment your code, which you are beginning to do, but not enough.

I created a fiddle with your code and my comments in-line, but here’s the comments pulled out with relevant code for brevity:

REDUCE callbacks with two parameters should be written as: myCallback(accumulator, item) { //expression goes here } Since the operation you’re performing on item and total is addition, and thus obeys the commutative property, it still returns the correct result, but you should google “mdn reduce” to learn more about the correct syntax of this important function. */

  cidtotal = cidValues.reduce(function(item, total) {
    return item + total;
  }, 0);

In the final top-level else if (change < cidtotal):

    for (var y = 0; y < currencyValues.length; y++) {
        if (currencyValues[y] >= change) {
        currencyValues.splice(y, 1);
        cidValues.splice(y, 1);
      }
    }

The entire point of this first for loop is to figure out what the endpoints of iteration should be in the next for loop farther down. Rather than incurring a bunch of costly splice operations, you could turn this into a while loop that, upon completion, has a variable set to that value:

var indexToStart = 0; while ( currencyValues[indexToStart++] >= change ){}
//From this point in the code, indexToStart is the first one where
//currencyValues[indexToStart] < change, so you could use it in your for loop like this:
for (var i=indexToStart; i<currencyValues.length; i++){...} 

Alternatively, you could use Array.prototype.filter for cleaner code currencyValues.filter( billOrCoin => billOrCoin > change );

You’re doing better with your variable names, but they could still use some improvement:

   for (var i = 0; i < currencyValues.length; i++) {
      divider.push(Math.round(cidValues[i] / currencyValues[i]));
      //divider is the value of cidValues / currencyValues

Your comment tells me that divider is not an array of divisors, but quotients, so using the arithmetic names is not only unhelpful in this case, it is wrong. The quotient tells me how many currency units make up the monetary value in that slot of the change drawer. howManyUnitsInSlot, howManyBillsOrCoinsInSlot, or numUnitsInSlot are decent names because they speak to the abstraction we are modeling: a cash register change drawer. As for “sum”, I always want to know what a variable is the sum OF: sumOfChangeMade?

      for (var j = 1; j <= divider[i]; j++) {
          /*MY COMMENTS*/
          /* added a debugging statement*/
      		console.log("inside for loop, j:", j,"divider[i]:",divider[i], "currency:", currencyValues[i]);
          while ((sum + (currencyValues[i] * j)) <= change) {
          	sum = sum + (currencyValues[i] * j);
            console.log("sum:", sum);
        }
      }

LOOK AT THE CONSOLE. See how much wasted computation there is and also see whether the outer for loop is accomplishing anything. Ask yourself what the value of j is when the while loop above executes. As to why it’s not stopping at the appropriate value for sum, I suspect it has to do with floating point errors. At one point, the console is adding dimes and goes from sum: 96.6 to sum: 96.69999999999999

So basically my logic is correct? If I were to round of the value to two decimal points would the code work as intended?
As to the variable names i will try to name them reasonably from now.
The filter statement is much more simpler than indexToStart one so I will stick to that.
j basically iterates through the divider values so if 20 x 3 = 60, currencyValues[i]*j will test it for all possible j’s to output the maximum possible value for the sum to equal the change value.
sum is the total value of the change made by us.

Your logic is very much a shotgun approach. Which is worse than mere brute force. Like I told you before, if you LOOK AT THE CONSOLE, my debugging statement shows you that all the work is being done in the while loop, and the for loop does basically nothing. Which means that you don’t understand why you really wrote it. You are coding first and planning second. There are concepts taught in CS courses, like EdX’s free CS50 course, like “top-down programming” and “pseudocode” that I don’t think you know about, because of the data you’ve provided in this thread about your approach to problems. Like many who stumbled into coding (myself included), you need a formal Intro to CS course to improve your programming. If programming == algorithm/data structure design + coding, it’s the former part you lack. I do not mean this as an insult. I’m trying to get you to save your time by guiding you to a path that fills in what you don’t know you need to learn.

Now to the specifics:

  • I can’t say for certain what would fix it. I’m not going to debug your code for you on a certificate project. That would be academically dishonest. I can give you my experience and hints. Try it and see if it works. If you need help figuring out how to round to the nearest hundredth, I can help you with that pattern in Javascript.
  • Array functions are an algorithm designer’s dream. They take the code boilerplate out of the way to let us read the logic clearly. I did this whole project using array functions.
  • I understood what you were trying to do with sum, but your assignment statement for sum is what makes the for loop irrelevant. Also, from an algorithm design perspective, is that how YOU make change? Let’s say you need to make 63 dollars in change. Do you count up all the 20s in the slot, and put them down if there aren’t enough, or do you ask yourself, “I need 3 twenty-dollar bills, are there enough in the drawer slot?” That would lead to computational efficiency and a logic flow that other programmers would recognize, since we are, after all, creating an abstraction of a cash register. If you design it that way, you will still see the expression analogous to currencyValues[i]*j, but you will perform it only once.

Ok. Thanks for being honest with me. I didn’t have any data structures background and I was expecting the course to teach me that.
And about the logic, I will try to implement it the correct way as you have hinted. I know it’s painful for you to read my pathetic code so thanks for being there still.