2012-05-28 89 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