How to Randomly generate a new list of items but not select previous item that has been selected?

Question:

I’m creating some new algorithms for my project (Food App Generator) and I run into this problem of generating random new list from a pre-set dictionary of amount of same item I want to appear through out a week while not allowing the previous item to be the same.

Down below dictionary specifies food and amount of times it should be used. Biggest problem I’m running into is that if I’ve picked Potato Spaghetti and Potato again I’m left with rice which means I’m now stuck in a permanent while loop.

main = {'Potato': 2, 'Rice': 2, 'Spaghetti': 1}

I’m really stuck on this and IDK how to solve this issue. I tried ChatGPT and nothing useful came out from there as anything he provided = to more errors rather then solutions and over complicated functions that are 50+ lines.

Many Thanks in advance.

My Code:

days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
main = {'Potato': 2, 'Rice': 2, 'Spaghetti': 1}
meat = {'Chicken': 2, 'Salmon': 2, 'Beef': 1}
veg = {'Corn & Broccoli': 2, 'Prawn Bit Root Salad': 1, 'Small Corn & Broccoli': 2}

list_of_all_food_items = [main, meat, veg]

before_picked_item = []

days_to_generate_for = 5

def get_random_item(items: dict) -> str:
  item = rand.choice(list(items.keys()))

  while check_if_item_has_been_used_last(item) == True:
    item = rand.choice(list(items.keys()))
      
  before_picked_item.append(item)
  items[item] -= 1
  if (items[item] == 0):
    del items[item]
  return item

def check_if_item_has_been_used_last(item: str) -> bool:
  if len(before_picked_item) == 0:
    return False
  if item == before_picked_item[len(before_picked_item) - 1]:
    return True
  else:
    return False

def generate_random_days() -> dict:
  days_generated = []
  for food_type in list_of_all_food_items:
    random_foods = []
    for i in range(days_to_generate_for):
      random_foods.append(get_random_item(food_type))
      if (len(random_foods) == days_to_generate_for):
        days_generated.append(random_foods)
        print(days_generated)

generate_random_days()

Answers:

Why does it have to be purely random? You would maximize your chances to avoid choosing the same meal twice in a row if you picked among items that are available in larger quantities.

Edit: rewriting your code so that check_if_item_has_been_used_last isn’t needed anymore:

import random as rand
days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
main = {'Potato': 2, 'Rice': 2, 'Spaghetti': 1}
meat = {'Chicken': 2, 'Salmon': 2, 'Beef': 1}
veg = {'Corn & Broccoli': 2, 'Prawn Bit Root Salad': 1, 'Small Corn & Broccoli': 2}

list_of_all_food_items = [main, meat, veg]

before_picked_item = ['']

def get_random_item(items: dict) -> str:
  lst = []
  i = 0
  while not lst and i < max(items.values()):
    lst = [k for k, v in items.items()
            if k != before_picked_item[-1] and v==max(items.values())-i]
    i+=1
  item = rand.choice(lst)
      
  before_picked_item.append(item)
  items[item] -= 1
  if (items[item] == 0):
    del items[item]
  return item

def generate_random_days(days_to_generate_for) -> dict:
  days_generated = []
  for food_type in list_of_all_food_items:
    random_foods = []
    for i in range(days_to_generate_for):
      random_foods.append(get_random_item(food_type))
      if (len(random_foods) == days_to_generate_for):
        days_generated.append(random_foods)
        print(days_generated)

generate_random_days(5)

Output (first run):

[['Potato', 'Rice', 'Potato', 'Rice', 'Spaghetti'], ['Salmon', 'Chicken', 'Salmon', 'Chicken', 'Beef'], ['Small Corn & Broccoli', 'Corn & Broccoli', 'Small Corn & Broccoli', 'Prawn Bit Root Salad', 'Corn & Broccoli']]

Output (second run):

[['Rice', 'Potato', 'Spaghetti', 'Potato', 'Rice'], ['Salmon', 'Chicken', 'Salmon', 'Chicken', 'Beef'], ['Corn & Broccoli', 'Small Corn & Broccoli', 'Prawn Bit Root Salad', 'Small Corn & Broccoli', 'Corn & Broccoli']]
Answered By: Tranbi
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.