Getting multiple inputs from the loop

def calorie_counter():
    # Create widgets outside the loop
    food_type_widget = st.empty()
    frequency_per_week_widget = st.empty()
    times_per_day_widget = st.empty()
    quantity_widget = st.empty()
    

    food_dataset = load_food_data()
    drop_down_column = food_dataset["Food_Name"]
   
    ft = []
    fpw = []
    tpd = []
    quan = []
 
    carbohydrates_value = 0
    protein_value = 0
    fat_value = 0
    fiber_value = 0
    total_weekly_calories = 0

    food_items = []


    num_food_items = st.number_input("Enter the number of food items: ", step = 1)


    counter = 0
    while counter < num_food_items:
        food_type = food_type_widget.selectbox("Select the type of food:", drop_down_column, key=f"food_type_input_{len(ft)}")
        frequency_per_week = frequency_per_week_widget.number_input("Enter the frequency per week for food:", key=f"frequency_per_week_input_{len(fpw)}", step=1)
        times_per_day = times_per_day_widget.number_input("Enter how many times per day for food:", key=f"times_per_day_input_{len(tpd)}", step=1)
        quantity = quantity_widget.number_input("Enter the quantity in grams for food:", key=f"quantity_input_{len(quan)}", step=1)

        food_items.append({
            'food_type': food_type,
            'frequency_per_week': frequency_per_week,
            'times_per_day': times_per_day,
            'quantity': quantity
        }) 

        ft.append(food_type)
        fpw.append(frequency_per_week)
        tpd.append(times_per_day)
        quan.append(quantity)
        
        counter += 1

In the above code, I need to get the number of food items from the user and using that I need to run the loop and get different food type, frequency per week, times per day and quantity value. But the problem is I couldnโ€™t get multiple values from the loop eventhough it is in a loop. The app is running locally in the streamlit version1.32.2

The key is to remember that a streamlit app just runs as a script from top to bottom. In your case, it doesnโ€™t stop to wait for input, it just keeps adding widgets where you told it to, so if you tell it to loop 3 times, it will write over the food_type_widget three times, and only show the last one.

One way to solve this is to use st.session_state to keep track of whatโ€™s been entered, and add a submit button that updates the list of foods, and then reruns the app again for the next entry.

import streamlit as st

def load_food_data():
    food_dataset = {
        "Food_Name": ["Apple", "Banana", "Orange", "Mango", "Pineapple"],
        "Carbohydrates": [25, 27, 21, 30, 22],
        "Protein": [1, 1, 1, 1, 1],
        "Fat": [0, 0, 0, 0, 0],
        "Fiber": [4, 3, 3, 4, 2],
    }

    return food_dataset

if "num_entered" not in st.session_state:
    st.session_state.num_entered = 0

if "food_items" not in st.session_state:
    st.session_state.food_items = []

def calorie_counter():

    food_dataset = load_food_data()
    drop_down_column = food_dataset["Food_Name"]

    ft = []
    fpw = []
    tpd = []
    quan = []

    num_food_items = st.number_input("Enter the number of food items: ", step = 1)

    # Create widgets outside the loop
    food_type_widget = st.empty()
    frequency_per_week_widget = st.empty()
    times_per_day_widget = st.empty()
    quantity_widget = st.empty()


    counter = 0
    if st.session_state["num_entered"] < num_food_items:
        food_type = food_type_widget.selectbox("Select the type of food:", drop_down_column, key=f"food_type_input_{len(ft)}")
        frequency_per_week = frequency_per_week_widget.number_input("Enter the frequency per week for food:", key=f"frequency_per_week_input_{len(fpw)}", step=1)
        times_per_day = times_per_day_widget.number_input("Enter how many times per day for food:", key=f"times_per_day_input_{len(tpd)}", step=1)
        quantity = quantity_widget.number_input("Enter the quantity in grams for food:", key=f"quantity_input_{len(quan)}", step=1)

        if st.button("Submit"):

            st.session_state.food_items.append({
                'food_type': food_type,
                'frequency_per_week': frequency_per_week,
                'times_per_day': times_per_day,
                'quantity': quantity
            })

            ft.append(food_type)
            fpw.append(frequency_per_week)
            tpd.append(times_per_day)
            quan.append(quantity)

            st.session_state["num_entered"] += 1

            st.rerun()
    else:
        st.write("No more food to enter")

    st.write("Food items entered")
    st.write(st.session_state.food_items)

calorie_counter()

Thank you for your solution and it worked. But now i have to use the values of the food_items dictionary for further operations.

  1. I need to pass them on to two other functions. By taking the details of the food items, frequency, times per day and quantity, I calculate the total calories consumed by a person in a week and their nutritional composition. But I could not add up the total calories consumed per week value (Program given below for understanding*). Is it because of the st.session_state function usage.
  2. Similarly, what if I donโ€™t know the number of food items to get in the first place in your given solution. How do we approach that too.
    Code*: (The food_items is passed as arguments in the following two functions)

def calculate_weekly_calories(food_items):
total_weekly_calorie = 0

food_dataset = load_food_data()

for food_item in food_items:
    food_type = food_item['food_type']
    frequency_per_week = food_item['frequency_per_week']
    times_per_day = food_item['times_per_day']
    quantity = food_item['quantity']

    st.write(food_type,frequency_per_week,times_per_day,quantity)

    # Filter the DataFrame based on the food_type
    food_row = food_dataset[food_dataset['Food_Name'] == food_type]

    st.write(food_row)

    # Check if the DataFrame is empty
    if not food_row.empty:
        # Calculate calories per serving
        calories_per_serving = (food_row['Calories']) * quantity
        st.write("Calories per serving",calories_per_serving)

        # Calculate total daily calories
        daily_calories = calories_per_serving * times_per_day
        st.write("daily calories",daily_calories)

        # Calculate total weekly calories for the current food item
        weekly_calories = daily_calories * frequency_per_week
        st.write("weekly calories",weekly_calories)

        total_weekly_calorie += weekly_calories
        st.write("total weekly calories",total_weekly_calorie)

    else:
        st.write(f"No data found for {food_type}")
st.write("Out of loop total week calorie",total_weekly_calorie)


return total_weekly_calorie

def calculate_nutritional_composition(food_items):
carbohydrates = 0
protein = 0
fat = 0
fiber = 0
food_dataset = load_food_data()

for food_item in food_items:
    food_type = food_item['food_type']
    frequency_per_week = food_item['frequency_per_week']
    times_per_day = food_item['times_per_day']
    quantity = food_item['quantity']

    # Filter the DataFrame based on the food_type
    food_row = food_dataset[food_dataset['Food_Name'] == food_type]


    # Check if the DataFrame is empty
    if not food_row.empty:
        # Calculate nutritional composition based on weekly calories
        carbohydrates += (food_row['Carbohydrates']) * quantity * frequency_per_week * times_per_day
        protein += (food_row['Protein']) * quantity * frequency_per_week * times_per_day
        fat += (food_row['Fat']) * quantity * frequency_per_week * times_per_day
        fiber += (food_row['Fiber']) * quantity * frequency_per_week * times_per_day
    else:
        st.write(f"No data found for {food_type}")

st.write(carbohydrates,protein,fat,fiber)

return carbohydrates, protein, fat, fiber

In the future, please make sure to format all your code as a code block using triple backticks ( `, no spaces)

All the information is stored in st.session_state.food_items, so you can simply loop through that list of dictionaries and do whatever you want with the info

for food_item in st.session_state.food_items:
    ...

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.