Troubleshooting a loop


#1

Hello, campers!

I’m using multiple online resources to learn JavaScript, and both FCC and codecademy have finally introduced me to the loop. I’ve decided to try out a mini-project that involves a loop.

On Sunday nights, I like to plan out what I’m going to be eating for lunch that week. Anal, I know, but I like to just grab a lunch and run out the door for work in the morning rather than waste money on takeout or unhealthy fast food everyday. So, I decided to create a system to randomly choose what I’m eating for lunch Monday-Friday based on the meals I have in my fridge.

I have the meals variable, an array of what’s in the fridge.

The weekday variable is an array of Monday through Friday.

And the last variable I can’t figure out how to incorporate into my loop is the weekdayLunch variable, the value of which is randomly selected from the meals array.

var meals = ["PB + J", "spinach salad with tofu", "granola and yogurt", "tofurkey sandwich", "leftover chili", "lentil soup", "breakfast burrito", "protein cookie"];

var weekday = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"];

var weekdayLunch = (Math.floor(Math.random) * meals.length);

for (var i = 0; i <= 4; i++ ) {
    console.log(weekday[i] +"'s lunch will be " + weekdayLunch);   
}

Here is what the above code returns:

Monday's lunch will be NaN
Tuesday's lunch will be NaN
Wednesday's lunch will be NaN
Thursday's lunch will be NaN
Friday's lunch will be NaN

Why is NaN coming up? Rather than NaN, I want it to be a random selection from the array defined in “meals”. Is this a simple problem I’m overlooking, or does my code require more of an overhaul?

Thanks for reading!

-Julianna


#2

Hi,
if you run your web browser console and check that random function, you’ll see it returns Nan.

so Nan multiply by any number will still be a Nan.

It’s a function so it needs parenthesis… i.e. Math.random( ) instead of just Math.random

Try it.

Math.floor(Math.random() * meals.length  )

#3

If you don’t want to have the same meal twice in the same week you could make your code more interesting and use the splice() method on your meals array inside the loop.


#4

Hey @jnelli you have a couple of issues that I cleaned up for you in your array.

First of all, you’re missing a functional set of parentheses on Math.random, and your parentheses for Math.floor should be wrapped around the product of multiplication (otherwise you would get 0 every time because by default Math.random generates a number between 0-1.

You should define weekdayLunch as such

var weekdayLunch = (Math.floor(Math.random() * meals.length));

That will get you a number between 0 and meals.length -1. The other problem I see is that now your program will print for example

Monday’s lunch will be 3!

which I don’t think is what you want.
To fix this, you should instead use weekdayLunch as an index using bracket notation, to make the statement in the for loop look like this:

console.log(weekday[i] +"'s lunch will be " + meals[weekdayLunch]); 

Best of luck! Always good to see new people starting to learn!


#5

I’m not too familiar with using the splice() method, so that’s a good reason for me to practice with it! I’ll try another variation using splice().


#6

Ahh, such a simple mistake!! Thank you for pointing that out.


#7

Keep in mind that the length of meals will change throughout so there’s that extra challenge.


#8

Thank you, I’m happy to be getting feedback! Now that my variable weekdayLunch is functioning as it should, I’m encountering the problem where the value of weekdayMeal will change, but it is the same value Monday through Friday! While I enjoy a good bowl of leftover chili, that’s not something I can eat for lunch all week. :slight_smile:

I’ll fiddle around and return to this thread should I need additional help, which is likely! Thank you again.


#9

I could individually print Monday through Friday with the randomized variable, but that takes away the need for a loop. And I’d rather define my variables and then execute the weeks’ meals all in one function.


#10

Well, I may need to come back to this one. I don’t know how to randomize the variable for each loop. Also can’t figure out why printed the variable to the console AND running my loop has the some outcome??

I know there is a solution, I’m just not sure if it’s something I’ve covered yet.

var meals = ["PB + J", "spinach salad with tofu", "granola and yogurt", "tofurkey sandwich", "leftover chili", "lentil soup", "breakfast burrito", "protein cookie"];

var weekday = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"];

var weekdayLunch = (Math.floor(Math.random() * meals.length));

for (var i = 0; i <= 4; i++ ) {
    console.log(weekday[i] +"'s lunch will be " + meals[weekdayLunch]);   
}


console.log(meals[weekdayLunch]);

This outputs to the following, where the loop goes through and prints each day of the week but the weekdayLunch value is the same for each loop iteration and the printed variable!

Monday's lunch will be spinach salad with tofu
Tuesday's lunch will be spinach salad with tofu
Wednesday's lunch will be spinach salad with tofu
Thursday's lunch will be spinach salad with tofu
Friday's lunch will be spinach salad with tofu
spinach salad with tofu

#11

You need to put your random function inside the loop so it changes for every iteration.


#12

You need to move the following line

var weekdayLunch = (Math.floor(Math.random() * meals.length));

into the for loop, because if not, weekdayLunch will always be the same meal index for each iteration of the for loop.

I would also recommend creating a function called getRandomMeal which would return a random meal. For example:

function getRandomMeal(meals) {
  return meals[Math.floor(Math.random() * meals.length)];
}

would be called from for loop like:

getRandomMeal(meals);

By creating a function and passing in a meals array, you could also create breakfastMeals, lunchMeals, and dinnerMeals arrays and the same function would still return a random meal from the corresponding meals array.


#13

You have various choices but two are at the top of my list:

  1. You create a randomPick function that selects a random element from an array; then, for each day of the week, you use that function to pick a random meal.

The problem? Repeated meals are possible.
Solution? To keep track of previously used random meals and repeat the process of picking until you’re left with no chance of picking again (exhaustive random picking).

  1. You “shuffle” the array of meals (randomise the order in which the elements of an array appear, like shuffling a deck of cards) using the Shunting-Yard Algorithm (most efficient algorithm to do this). Then, you can use the same index in the for loop to pick both the day of the week and the meal. This works because the order of the meals has been randomised.

This is a function which part of a library I’m working on using closures, that does what I described in the solution of the 2nd alternative (with a .pop instead of index):

import { shuffle } from './Array/shuffle.js'

// randomPicker :: [a] -> b -> (() -> a | b)
export function randomPicker(xs, fallback) {
  const shuffled = shuffle(xs)

  return function() {
    return shuffled.pop() || fallback
  }
}

You’d use it like this:

// randomMeal :: () -> String
const randomMeal = randomPicker(['sausages', 'roast beef', 'fried chicken'], 'No Meal')

console.log(randomMeal(), randomMeal(), randomMeal(), randomMeal(), randomMeal())
//> fried chicken, sausages, roast beef, No meal, No meal

The function can be altered to cycle again a new shuffled order when the first order exhausts etc.


#14

Hi all, thanks to everyone’s input I now have a piece of code functioning the way it should.

Next step is for me to take the strings chosen at random during each loop iteration, place this into an array and have each subsequent iteration ignore those values so that each loop will not have repeats. I likely will not tackle this tonight as I’m still early on in my JavaScript lessons. I’ve just wrapped up the section on for loops and am now moving on to while loops.

Thanks again!