...

View Full Version : (Simple?) Assigning array values in a compounding loop - keep getting NaN or undefine



shelzmike
09-25-2011, 02:58 AM
Okay, I am taking a js class and there is one minor bug that is driving me crazy with this assignment.

First, here is the code I wrote, then my question:



var games = ["Jacks","Chutes and Ladders","Extreme Uno","Bopit","Barbie Doll"];
var price = [4.00,15.99,25.00,27.99,32.00];
var inventory = [40,15,30,20,40];

//I could not figure out how to make this work without assigning values first. It was giving NaN.
var subtotal = [0,0,0,0,0];
var qtySold = [0,0,0,0,0];

function chooseItem() {
var answer = 0;

while (answer != 6) {
var orderForm = "Choose a number below:\n";

for (var i=0; i<games.length; i++) {
orderForm = orderForm + (i + 1) + ".) " + games[i] + ": # in stock: " + inventory[i] + "\n";
}
orderForm = orderForm + "6.) Show Sales Summary";
answer = prompt(orderForm);
answer = parseFloat(answer);

if(answer != 6 && answer >= 1 && answer < games.length+1) {
var qty = prompt("How many " + games[answer-1] + " would you like?");
qtySold[answer-1] = parseFloat(qtySold[answer-1]) + parseFloat(qty);
subtotal[answer-1] = qtySold[answer-1] * price[answer-1];
} else if (answer < 1 || answer > 6) {
alert("Invalid Answer");
} else {
alert("Click OK to see your summary:");
}
}
var summary = "Your Sales: \n";
for (var j=0; j<qtySold.length; j++) {
summary = summary + qtySold[j] + " " + games[j] + " at " + currency(price[j]) + " each for a total of " + currency(subtotal[j]) + "\n";
}
alert(summary);
}

So basically, the arrays subtotal and qtySold need to retain values in case the "customer" chooses to add more of the same item in each order. What you see above works; however, when I alert the summary, it lists all of the items, even if there were none ordered. It simply says 0, but that is not what I want.

Basically, I only want the total to reflect only the items that were actually selected.

I do not what to do it this way:

var subtotal = [0,0,0,0,0];
var qtySold = [0,0,0,0,0];

I can effectively do this by NOT assigning any values to the qtySold array in the beginning: i.e. doing it this way:


var subtotal = new Array();
var qtySold = new Array();


The only problem is that when I do this, I get NaN at this point:


qtySold[answer-1] = parseFloat(qtySold[answer-1]) + parseFloat(qty);
subtotal[answer-1] = qtySold[answer-1] * price[answer-1];


obviously, this is because I am referencing qtySold[answer-1]
directly in the loop - so the first time through, there is nothing assigned.

I can't (just before this line) assign 0 to each array item - to get it defined because if the user goes back in and adds more, it will always reset the number back to 0, which is not what I wanted.

I tried adding an if..else statement instead, but cannot figure out how to get that to work?

What are my options here?

Thanks!

Mike

Old Pedant
09-25-2011, 03:54 AM
Nice question.

*Personally*, I would have simply done this, at the top of the code:


var subtotal = [];
var qtySold = [];
for ( var n = 0; n < games.length; ++n )
{
subtotal[n] = 0;
qtySold[n] = 0;
}


But there's a certain elegance in trying to do this "on the fly".

I can think of various ways, but maybe start with this:

First, just do


var subtotal = [];
var qtySold = [];
at the top of the code, to ensure that the variables are arrays.

And then maybe

if(answer != 6 && answer >= 1 && answer < games.length+1) {
try { /* see if we can get a value from the expected array slot */
var ignored = subtotal[answer-1];
} catch( alsoIgnored ) {
/* assume that the error was because that slot didn't exist yet */
/* so initialize it */
subtotal[answer-1] = 0;
qtySold[answer-1] = 0;
}
var qty = prompt("How many " + games[answer-1] + " would you like?");
qtySold[answer-1] = parseFloat(qtySold[answer-1]) + parseFloat(qty);
subtotal[answer-1] = qtySold[answer-1] * price[answer-1];
...

??

Old Pedant
09-25-2011, 04:03 AM
Personally, I would have done this:


// create a constructor for a Game object:
function Game( Name, Price, Qty )
{
this.name = Name;
this.price = Price;
this.qty = Qty;
this.qtySold = 0;
this.subtotal = 0.0;
}
var games = [
null, /* so we don't have to keep using answer-1! */
new Game("Jacks",4.00,40),
new Game("Chutes and Ladders",15.99,15),
new Game("Extreme Uno",25.00,30),
new Game("Bopit",27.99,20),
new Game("Barbie Doll",32.00,49)
];

And then that same part of your code would look like:


if( answer >= 1 && answer < games.length)
{
var game = games[answer]; // see? no -1 needed because of the null
var buy = prompt("How many " + game.name + " would you like?");
game.qtySold += parseInt(buy); // int because you can't buy half a game!
game.subtotal = game.qtySold * game.price;
...

But don't turn that in for homework! It's way beyond where you are now. Just think about it for the future.

shelzmike
09-25-2011, 06:50 AM
HaHa! Yeah, I wouldn't turn that in for my homework! It's actually not that far ahead of where we are (and the instructor pretty much let's us up the ante, if you will, if we have the ability and time). I have found that I have quite a bit more experience than anyone else in the class and do way more than is expected on the assignments (sometimes to my detriment); I have been designing sites for the past 6 or 7 years and while I have used some JS in the past, never really "understood" it proficiently. Plus I needed one more credit to finish my B.S. in CMIS.

Anyway, I initially started with using a constructor, but realized when it came time for the "ordering" aspects (at least the way he wanted us to do it) I was so lost. The starting examples he gave were using arrays so I just went with that. Your example makes it really clear though and I am tempted to start over - haha. But I won't because this is all due tomorrow. I already drove into the mud, might as well continue on.

I figured out what is probably a horribly non-graceful way to do it, but it does work.

I was using Firebug and realized that just before this code ran that each of the indexes were listed as undefined. So, just before this code, I check to first see if the index is undefined. If so, assign it 0 so that the math will result in a number (instead of NaN). If the index is NOT undefined, continue on as usual.

Here is what I came up with:


var subtotal = new Array();
var qtySold = new Array();

....

if(answer != 6 && answer >= 1 && answer < games.length+1) {
var qty = prompt("How many " + games[answer-1] + " would you like?");
//see, here is the ugly stuff - but at least I know that! I am too much of a perfectionist to do this in practice.
if (typeof(qtySold[answer-1]) === "undefined") {
qtySold[answer-1] = 0;
} else {
qtySold[answer-1] = qtySold[answer-1];
}
qtySold[answer-1] = parseFloat(qtySold[answer-1]) + parseFloat(qty);
subtotal[answer-1] = qtySold[answer-1] * price[answer-1];
} else if (answer < 1 || answer > 6) {
alert("Invalid Answer");
} else {
alert("Click OK to see your summary:");
}


Thanks again for your help. I am not the type to just come on the forums and get answers without even trying on my own first. In fact, I only come on at last resort, like today, but I am sure you will see me around for the next 10 weeks!

Have a good weekend!

Mike

shelzmike
09-25-2011, 07:03 AM
OK, actually, I spoke too soon. If I choose only the first item and the second item (or any consecutive indexes) , it works fine. However, if I choose say the first and third, then I again the NaN in the summary.

I think at this point, I am just going to not push the issue - go ahead an assign the indexes 0 from the start and take the few points off, knowing this is not the best solution anyway.

Oh well, at least I learned how to check if an index is undefined!

Old Pedant
09-26-2011, 02:20 AM
I really don't see what's wrong with my first suggestion: Init the arrays to the same size as the Games array. In most any other language, that's what you'd have to do. JS is too flexible, allowiing you to assign to array elements that don't yet exist.

shelzmike
09-27-2011, 05:14 PM
Actually, you are right - your first suggestion does work but the only real difference is that it looks better than [0,0,0,0,0]. However, it still does not solve the problem of having the summary have "0" entries for items not selected.

Either way, I just left it how it was. I went about 500% above and beyond what was required for this assignment anyway and the instructor is perfectly fine with the way I have it.

In hindsight, I have learned that #1 - this would have been better with objects and a constructor (though I am not as comfortable with those yet), and #2 - the reason that I am getting the "0" entries at the summary screen is because you cannot have an array that looks like this: [15, null, 8, null, null, 7). Or is that wrong? It seems that the reason this happens is that when I select an item that is in the [0] position and then another at the [2] position, it automatically creates the [1] position and assigns "0" as the value.

I could probably come up with some overly-complicated code in the creation (through concatenation) that leaves out any of the array items that are ==0. (i.e. in the following code:)


var summary = "Your Sales: \n";

for (var j=0; j<qtySold.length; j++) {
summary = summary + qtySold[j] + " " + games[j] + " at " + currency(price[j]) +
" each for a total of " + currency(subtotal[j]) + "\n";
}
alert(summary);
alert("The total cost of your items is " + currency(total) +
"\nThank you for shopping with us!!");
}

Thanks again for your help!

Mike

shelzmike
09-27-2011, 05:22 PM
Wowww - I cannot believe how easy that was! Forums are good because sometimes I figure things out by simply typing the logic out! All I had to do was add an if statement and now the summary ONLY shows what has been selected!

Success!!


var summary = "Your Sales: \n";
for (var j=0; j<qtySold.length; j++) {
if (qtySold[j] != 0) {
summary = summary + qtySold[j] + " " + games[j] + " at " +
currency(price[j]) + " each for a total of " + currency(subtotal[j]) + "\n";
}
}
alert(summary);
alert("The total cost of your items is " + currency(total) + "\nThank you for shopping with us!!");
}

Thanks again!

Mike

Old Pedant
09-27-2011, 10:05 PM
Your solution clearly works, but...


you cannot have an array that looks like this: [15, null, 8, null, null, 7]. Or is that wrong?

Wrong. Sure you can. And it's actually a really good technique.

So you could have done

var subtotal = [];
var qtySold = [];
for ( var n = 0; n < games.length; ++n )
{
subtotal[n] = null;
qtySold[n] = null;
}
...
if(answer != 6 && answer >= 1 && answer < games.length+1) {
var qty = prompt("How many " + games[answer-1] + " would you like?");
if ( qtysold[answer-1] == null ) qtysold[answer-1] = 0;
qtySold[answer-1] += parseInt(qty);
subtotal[answer-1] = qtySold[answer-1] * price[answer-1];
...

or you could do it all in one line


qtySold[answer-1] = (qtySold[answer-1]==null ? 0 : qtySold[answer-1]) + parseInt(qty);


NOT suggesting any of this. Just pointing out that null array elements can actually be useful.

shelzmike
09-27-2011, 10:37 PM
Thanks for that. I thought that it sounded wrong once I typed it. The problem then was assigning an initial value to the array item before trying to add a quantity to it. That is why I was getting NaN I believe.

Either way, I am finished with this one and will pocket this info for future use. I really appreciate your help on this and hopefully others will be helped by it in the future.

New assignments start this weekend, so I am sure I will be around :)

Mike



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum