コードにはいくつかの一般的な問題があるため、それらを修正することから始めましょう。
ユーザーに提示したいアイテムが複数あり、それらの値をハードコーディングしています。何度も繰り返す必要があるため、これには多くの労力がかかります。あなたの選択行を見てください、それらはすべて基本的に同じことになります。また、説明とコードで数字が何にリンクするかを定義することも繰り返します。これをデータ構造で単純化してみましょう。
ここでは、すべてのオプションのリストを作成します。これは、指定された食品の名前とアイテムのセットを定義するタプルのリストです。ここでは注文する必要がないので、セットを使用します。
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
オプションの番号を取得するためにビルトインenumerate()
を使用していることに注意してください。1 から開始したい場合、Python は通常 0 からカウントするので、それも渡します。
これで出力が得られますが、既存のコードを変更せずに項目を簡単に追加できるようになりました。前と同じように尋ねると、if
/elif
の負荷の代わりに、リストから与えられたインデックスを簡単に取得できます。最初に文字列を数値に変更し、次に数値を削除する必要があります (Python は 0 からカウントするため)。これにより、次のことがわかります。
_, values = options[int(choose)-1]
(最初の値は必要のない名前であるため、タプルのアンパックを使用して無視します)。
唯一の問題は、たとえば、ユーザーが範囲外の数字や単語を入力した場合にどうなるかです。int に変換して使用する前に確認することもできますが、単純に試して、失敗時にスローされた例外をキャッチするのは Pythonic です。例えば:
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."
これは機能し、複数の購入行を出力しますが、最適ではありません。必要なすべてのアイテムを含む 1 つの大きな買い物リストを作成することをお勧めします。
これは、ループしながらすべての項目のセットを作成し、そのセットを出力することで作成できます。
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 には、リスト (リスト内包表記) を構築する機能が組み込まれています。この操作は次のように実行できます。
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()
私たちが望んでいることを正確に行うわけではないことに注意してください。ここには 2 つのオプションがあります。最初にジェネレーター式を使用してセットを結合してから、結合された文字列を結合することができます。
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
) が、それが基本的な考え方です。