How to add string to a list if the strings exist in the dictionary keys that consist of one or more words dynamically

Question:

I want to iterate some string from voice input through python dict that contains one, two or more word in key and add the strings to a list if exist in dict keys. I know how to add the string (voiceinput) to a new list (fruit_cart), if it only contains one word in dict key (dict_fruit) and iterating its values, like this:

# one word only of dict keys
dict_fruit = {"apple": 2, "melon": 6, "mango": 3, "banana": 4, "grape": 5}

voiceinput = 'I want 2 Melons 3 apples 1 mango 4 grapes and 1 banana'

def show_order(cart, quantity, price, gross_price):
    print(); print("PYTHON FRUIT STORE".center(55, " "))
    print("=" * 55); print(f"{'# ':<5}{'Item':<15}{'Item':<10}{'Order':<10}{'Order':>8}")
    print(f"{' ':<5}{'Name':<15}{'Price':<10}{'Quantity':<10}{'Price':>8}"); print("-" * 55)
    total_price = 0
    for idx, item in enumerate(cart):
        print(f"{idx + 1:<5}{item:<15}{'$':<2}{price[idx]:>2}{quantity[idx]:^15}{'$':>3} {gross_price[idx]:.2f}")
        total_price = total_price + gross_price[idx]
    tax = 10 if total_price > 4.99 else 11
    vat = total_price * tax / 100
    final_price = total_price + vat
    print("-" * 55); print("tttttTotal Price           ", f"{'$':<1} {total_price:.2f}")
    print(f"tttttVAT {tax}%               ", f"{'$':<1} {vat:.2f}")
    print("tttttFinal Price           ", f"{'$':<1} {final_price:.2f}"); print()
    print("  Thank You  ".center(55, "="))
    return final_price

def order_process(userinput):
    userlist = [char.removesuffix("s") for char in userinput.lower().split()]
    fruit_cart = [item for item in userlist if item in dict_fruit]
    fruit_quantity = [int(num) for num in userlist if num.isdigit() and num != '0']
    if len(fruit_cart) != len(fruit_quantity) or len(fruit_quantity) == 0 or len(fruit_cart) == 0: return exit()
    fruit_price = [dict_fruit[item] for item in fruit_cart]
    gross_price = [qty * prc for qty, prc in zip(fruit_quantity, fruit_price)]
    return show_order(fruit_cart, fruit_quantity, fruit_price, gross_price)


order_process(voiceinput) if any(word in voiceinput for word in fruit) else exit()

For the two words, I’ve tried spliting the first word and second word into separate 2 list (first_word and second_word) and iterating them with tuples (fruit_color and fruit_names) then join them at the end (join_word and fruit_cart), but it seems it’s not the elegant way or solution since it works only on 2 words:

# two words only of dict keys    
dict_fruit = {"red apple": 2, "green apple": 2, "black grape": 5}
fruit_color = ('red', 'green', 'black')
fruit_names = ('apple', 'grape')

voiceinput = 'I want 3 green Apples 2 red apples and 1 black grape'


def order_process(userinput):
    userlist = [char.removesuffix("s") for char in userinput.lower().split()]
    first_word = [word for word in userlist if word in fruit_color]
    second_word = [word for word in userlist if word in fruit_names]
    if len(first_word) != len(second_word): return exit()
    join_word = [word for pair in zip(first_word, second_word) for word in pair]
    fruit_cart = [' '.join(word) for word in zip(join_word[0::2], join_word[1::2])]
    fruit_quantity = [int(num) for num in userlist if num.isdigit() and num != '0']
    if len(fruit_cart) != len(fruit_quantity) or len(fruit_quantity) == 0 or len(fruit_cart) == 0: return exit()
    elif not any(word in fruit_cart for word in dict_fruit): return exit()    
    fruit_price = [dict_fruit[item] for item in fruit_cart]
    gross_price = [qty * prc for qty, prc in zip(fruit_quantity, fruit_price)]
    return show_order(fruit_cart, fruit_quantity, fruit_price, gross_price)


order_process(voiceinput) if any(word in voiceinput for word in fruit) else exit()

How if the strings and dict keys consists 1, 2, or more words like this:

dict_fruit = {"red apple": 2, "green apple": 1, "melon": 6, "mango": 3, "banana": 4, "black grape": 5}
voiceinput = 'I want 2 red Apples 3 mangos 1 melon and 4 black grapes'

then add the strings (voiceinput) if it exist in dict keys (dict_fruit) or vice-versa to a new list (fruit_cart) like below:

fruit_cart = ['red apple', 'mango', 'melon', 'black grape']

I know the code is messy, I’m new to python by the way.

Asked By: Arifa Chan

||

Answers:

This workaround solve the 1, 2 or more words in dictionary by iterating the input with nested for loop and check the every possibilty of joined word for each splitted word to dict:

dict_fruit = {"red apple": 2, "green apple": 1, "melon": 6, "mango": 3, "banana": 4, "black grape": 5}
voiceinput = 'I want 2 red Apples 3 mangos 1 melon and 4 black grapes'  

def show_order(cart, quantity, price, gross_price):
    print(); print("PYTHON FRUIT STORE".center(55, " "))
    print("=" * 55); print(f"{'# ':<5}{'Item':<15}{'Item':<10}{'Order':<10}{'Order':>8}")
    print(f"{' ':<5}{'Name':<15}{'Price':<10}{'Quantity':<10}{'Price':>8}"); print("-" * 55)
    total_price = 0
    for idx, item in enumerate(cart):
        print(f"{idx + 1:<5}{item:<15}{'$':<2}{price[idx]:>2}{quantity[idx]:^15}{'$':>3} {gross_price[idx]:.2f}")
        total_price = total_price + gross_price[idx]
    tax = 10 if total_price > 4.99 else 11
    vat = total_price * tax / 100
    final_price = total_price + vat
    print("-" * 55); print("tttttTotal Price           ", f"{'$':<1} {total_price:.2f}")
    print(f"tttttVAT {tax}%               ", f"{'$':<1} {vat:.2f}")
    print("tttttFinal Price           ", f"{'$':<1} {final_price:.2f}"); print()
    print("  Thank You  ".center(55, "="))
    return final_price

def order_process(userinput):
    userlist = [char.removesuffix("s") for char in userinput.lower().split()]
    fruit_cart = [
                   ' '.join(userlist[i:i+j])
                   for i in range(len(userlist))
                   for j in range(1, len(userlist) - i + 1)
                   if ' '.join(userlist[i:i+j]) in dict_fruit
                 ]
    fruit_quantity = [int(num) for num in userlist if num.isdigit() and num != '0']
    if len(fruit_cart) != len(fruit_quantity) or len(fruit_quantity) == 0 or len(fruit_cart) == 0: return exit()
    elif not any(word in fruit_cart for word in dict_fruit): return exit()    
    fruit_price = [dict_fruit[item] for item in fruit_cart]
    gross_price = [qty * prc for qty, prc in zip(fruit_quantity, fruit_price)]
    return show_order(fruit_cart, fruit_quantity, fruit_price, gross_price)


order_process(voiceinput) if any(word in voiceinput for word in dict_fruit) else exit()

However, if there’s a word in input that contains word of two words key in dict this code ends because the length of fruit_cart and fruit_quantity aren’t the same due to that one word were not added to the fruit_cart:

dict_fruit = {"red apple": 2, "green apple": 1, "melon": 6, "mango": 3, "banana": 4, "black grape": 5}
voiceinput = 'I want 1 apple 2 red Apples 3 mangos 1 melon and 4 black grapes'

# userlist = ['i', 'want', '1', 'apple', '2', 'red', 'apple', '3', 'mango', '1', 'melon', 'and', '4', 'black', 'grape']
# fruit_cart = ['red apple', 'mango', 'melon', 'black grape']
# fruit_quantity = [1, 2, 3, 1, 4]

Even though word has been added to the dict, e.g ‘apple’:

dict_fruit = {"apple": 1, "red apple": 2, "green apple": 1, "melon": 6, "mango": 3, "banana": 4, "black grape": 5}
voiceinput = 'I want 1 apple 2 red Apples 3 mangos 1 melon and 4 black grapes'

# userlist = ['i', 'want', '1', 'apple', '2', 'red', 'apple', '3', 'mango', '1', 'melon', 'and', '4', 'black', 'grape']
# fruit_cart = ['apple', 'red apple', 'apple', 'mango', 'melon', 'black grape']
# fruit_quantity = [1, 2, 3, 1, 4]
Answered By: Arifa Chan

This is a suitable job for regular expressions (regex).

For dict_fruit = {"red apple": 2, "green apple": 1, "melon": 6, "mango": 3, "banana": 4, "black grape": 5},
the appropriate regex would be
(d+) (red apple|green apple|melon|mango|banana|black grape),
which can be built with
f"(\d+) ({'|'.join(dict_fruit.keys())})".

import re

dict_fruit = {"red apple": 2, "green apple": 1, "melon": 6, "mango": 3, "banana": 4, "black grape": 5}
voiceinput = 'I want 1 apple 2 red Apples 3 mangos 1 melon and 4 black grapes'

# dict_fruit = {"red apple": 2, "green apple": 1, "melon": 6, "mango": 3, "banana": 4, "black grape": 5}
# voiceinput = 'I want 1 apple 2 red Apples 3 mangos 1 melon and 4 black grapes'

# dict_fruit = {"apple": 1, "red apple": 2, "green apple": 1, "melon": 6, "mango": 3, "banana": 4, "black grape": 5}
# voiceinput = 'I want 1 apple 2 red Apples 3 mangos 1 melon and 4 black grapes'

def show_order(cart, quantity, price, gross_price):
    print(); print("PYTHON FRUIT STORE".center(55, " "))
    print("=" * 55); print(f"{'# ':<5}{'Item':<15}{'Item':<10}{'Order':<10}{'Order':>8}")
    print(f"{' ':<5}{'Name':<15}{'Price':<10}{'Quantity':<10}{'Price':>8}"); print("-" * 55)
    total_price = 0
    for idx, item in enumerate(cart):
        print(f"{idx + 1:<5}{item:<15}{'$':<2}{price[idx]:>2}{quantity[idx]:^15}{'$':>3} {gross_price[idx]:.2f}")
        total_price = total_price + gross_price[idx]
    tax = 10 if total_price > 4.99 else 11
    vat = total_price * tax / 100
    final_price = total_price + vat
    print("-" * 55); print("tttttTotal Price           ", f"{'$':<1} {total_price:.2f}")
    print(f"tttttVAT {tax}%               ", f"{'$':<1} {vat:.2f}")
    print("tttttFinal Price           ", f"{'$':<1} {final_price:.2f}"); print()
    print("  Thank You  ".center(55, "="))
    return final_price

def order_process(userinput):
    matches = re.findall(f"(\d+) ({'|'.join(dict_fruit.keys())})", userinput.lower())
    fruit_quantity, fruit_cart = zip(*((int(quantity), fruit) for quantity, fruit in matches))
    fruit_price = [dict_fruit[item] for item in fruit_cart]
    gross_price = [qty * prc for qty, prc in zip(fruit_quantity, fruit_price)]
    return show_order(fruit_cart, fruit_quantity, fruit_price, gross_price)


order_process(voiceinput) if any(word in voiceinput for word in dict_fruit) else exit()
Answered By: aaron