2012-05-28 94 views
2

我通過製作小程序來學習Python(以及一般的編程)。以下是一個基本的購物計劃,它將返回基於所選食物購買的物品列表。Python中的購物清單

我想改善它,並允許用戶一次選擇幾種食物(例如,用戶輸入將是「1,2,3」)並基於此返回成分列表。

我應該採取什麼樣的方法?我使用Python 2.7,這是我的現有代碼:

mm_soup = ['minced meat', 'potatoes', 'frozen vegetable'] 
sunday_soup = ['chicken with bones', 'noodles', 'soup vegetable'] 
gulas = ['pork meat', 'food cream', 'potatoes', 'onion', 'frozen peas'] 

print "What would you like to cook on weekend?" 
print "Here are the options:" 
print "1. Minced Meat Soup" 
print "2. Sunday Soup" 
print "3. Gulas" 

choose = raw_input("> ") 

if choose == '1': 
    print "Buy", ", ".join(mm_soup) + "." 

elif choose == '2': 
    print "Buy", ", ".join(sunday_soup) + "." 

elif choose == '3': 
    print "Buy", ", ".join(gulas) + "." 

else: 
    print "Hmmm. No such food on the list." 
+0

我不確定什麼被認爲是一個家庭作業的問題,但這不是一項家庭作業(如Boud標記)。 – finspin

+0

如果它被誤刪,請隨時更改。 –

回答

7

你的代碼有一些常見的問題,所以我們先來解決這些問題。

您有多個項目要呈現給用戶,並且您正在對這些值進行硬編碼。這會讓你付出很大的努力,因爲你不得不重複自己。看看你的選擇路線,他們都基本上是一樣的。您也可以通過定義您的描述中和編碼中的數字鏈接來重複自己。我們試着用數據結構來簡化它。

在這裏,我們列出所有選項 - 元組列表,定義給定食物的名稱和項目集。我們在這裏使用一套,因爲我們不需要訂購物品。

options = [ 
    ("Minced Meat Soup", {'minced meat', 'potatoes', 'frozen vegetable'}), 
    ("Sunday Soup", {'chicken with bones', 'noodles', 'soup vegetable'}), 
    ("Gulas", {'pork meat', 'food cream', 'potatoes', 'onion', 'frozen peas'}), 
] 

這給了我們一個很好的數據結構。

然後我們就可以使我們的問題,而不是手動構建它,我們可以從我們的使用循環選項列表構造它:

print "What would you like to cook on weekend?" 
print "Here are the options:" 
for option, (name, values) in enumerate(options, 1): 
    print str(option)+". "+name 

注爲了使用the enumerate() builtin給我們的號碼選項。正如你想從1開始,Python通常從0開始計數,我們也通過它。

這給了我們我們的輸出,但我們現在可以輕鬆地添加更多項目而無需修改現有代碼。我們問以前一樣,然後,而不是加載if/elif s,我們可以簡單地從列表中獲得他們給我們的索引。我們首先必須將字符串更改爲一個數字,然後拿走一個(如Python從0開始計數)。這給了我們:

_, values = options[int(choose)-1] 

(使用元組解包忽略第一個值,因爲它是我們不需要的名稱)。

現在唯一的問題是,例如,如果用戶輸入的數字超出範圍或單詞,會發生什麼情況。在轉換爲int並使用它之前,您可以檢查它,但只是簡單地嘗試它並在發生故障時捕獲拋出的異常。例如:

try: 
    _, values = options[int(choose)-1] 
    print "Buy", ", ".join(values) + "." 
except (IndexError, ValueError): 
    print "Hmmm. No such food on the list." 

這使得整個程序要小得多,而且也注意到它是多麼容易增加新的項目,只需將它們添加到列表中。

那麼我們如何處理多個項目呢?那麼,現在也很簡單。我們可以把用戶的輸入,分割在逗號和剝離值,以消除任何空間,然後做我們做同樣的事情之前:

for choice in choose.split(","): 
    choice = choice.strip() 

    try: 
     _, values = options[int(choice)-1] 
     print "Buy", ", ".join(values) + "." 
    except (IndexError, ValueError): 
     print "Hmmm. No such food on the list." 

這工作,打印多買線,但它不是最佳,更好的辦法是製作一個包含所有需要物品的大型購物清單。

我們可以通過在我們循環時建立一組所有項目,然後打印出該組來創建該組。

shopping_list = [] 
for choice in choose.split(","): 
    choice = choice.strip() 
    try: 
     _, values = options[int(choice)-1] 
     shopping_list.append(values) 
    except (IndexError, ValueError): 
     print "Hmmm. No such food on the list." 

但是,這有點低效和醜陋。 Python有一些內置的功能來建立列表 - list comprehensions。我們可以這樣做:

try: 
    shopping_list = [options[int(choice.strip())-1][3] for choice in choose.split(",")] 
except (IndexError, ValueError): 
    print "Hmmm. No such food on the list." 

現在我們需要打印出列表中的所有值。請記住,這是一組套件,因此", ".join()不會完全符合我們的要求。我們在這裏有兩個選擇。我們可以使用一個生成器表達式先加入組,然後加入加入字符串:

print "Buy " + ", ".join(", ".join(values) for values in shopping_list) + "." 

或者,我們可以使用itertools.chain.from_iterable()返回一個扁平的迭代器:

print "Buy " + ", ".join(itertools.chain.from_iterable(shopping_list)) + "." 

這給我們:

import itertools 

options = [ 
    ("Minced Meat Soup", {'minced meat', 'potatoes', 'frozen vegetable'}), 
    ("Sunday Soup", {'chicken with bones', 'noodles', 'soup vegetable'}), 
    ("Gulas", {'pork meat', 'food cream', 'potatoes', 'onion', 'frozen peas'}), 
] 

print "What would you like to cook on weekend?" 
print "Here are the options:" 
for option, (name, values) in enumerate(options, 1): 
    print str(option)+". "+name 

choose = raw_input("> ") 

try: 
    shopping_list = [options[int(choice.strip())-1][1] for choice in choose.split(",")] 
    print "Buy " + ", ".join(itertools.chain.from_iterable(shopping_list)) + "." 
except (IndexError, ValueError): 
    print "Hmmm. No such food on the list." 

將會產生類似:

What would you like to cook on weekend? 
Here are the options: 
1. Minced Meat Soup 
2. Sunday Soup 
3. Gulas 
> 1, 2 
Buy potatoes, frozen vegetable, minced meat, chicken with bones, noodles, soup vegetable. 

這是簡短的,易於擴展和功能良好。還有其他一些問題可以處理(你想怎麼處理同一個項目的多個項目?你可能想看看collections.Counter),但這是基本的想法。

+0

哇,這是一個了不起的答案,我學到了很多東西。現在我需要多次重讀它並研究所有新概念。我認爲你的答案非常有價值,因爲你不僅提供了一個很好的解決方案,而且還教會了我如何用程序員的思維來應對所有這些挑戰。謝謝! – finspin

+0

其實我剛發現腳本的最終版本會產生一個錯誤:「name'shopping_list'沒有被定義」。我無法弄清楚爲什麼。 – finspin

+0

@finspin啊,是的,如果你輸入的不是列表中的內容,會發生,我會編輯修復。編輯:編輯。問題是shopping_list的定義在try塊中,但打印不是,所以如果失敗了,它會在嘗試使用不存在的變量時拋出錯誤。 –

1

我想你可以只拆分輸入的字符串,並通過它的元素進行迭代:

choose = raw_input("> ") 
for choice in choose.split(', '): #split by comma and space 
    if choice == '1': 
     print "Buy", ", ".join(mm_soup) + "." 
    elif choice == '2': 
     print "Buy", ", ".join(sunday_soup) + "."  
    elif choice == '3': 
     print "Buy", ", ".join(gulas) + "." 
    else: 
     print "Hmmm. No such food on the list." 

或類似的東西:

choose = raw_input("> "); 
selected = choose.split(', ') #split by comma and space 

suggestion = ''; 
if '1' in selected : 
    suggestion += ", ".join(mm_soup) 
if '2' in selected : 
    suggestion += ", ".join(sunday_soup) 
if '3' in selected : 
    suggestion += ", ".join(gulas) 

if len(suggestion) > 0: 
    print "Buy " + suggestion + "." 
else: 
    print "Hmmm. No such food on the list." 
+0

太好了,非常感謝。兩種解決方案都很好,我更喜歡第二種解決方案,因爲輸出更加優雅。我必須弄清楚如何用逗號分隔兩組或更多組成成分(第二個解決方案不會將它們分開)。但我會試着自己解決。我所追求的是邏輯。 – finspin