Pythonには、ループの構文が2つあります。
whileループは_回数が決まっていない_(カウントしない)繰り返しに、forループは_回数が決まっている_(カウントする)繰り返しに使います。
キーワードのbreak、continue、elseを使うと、ループの動作をカスタマイズできます。
range()とenumerate()は、ループのカウントやインデックス付けに役立ちます。
whileループは、loop expression(「テスト」)がboolean contextでTrueと評価されるかぎり実行を続け、Falseと評価されると終了します。
# Lists are considered "truthy" in a boolean context if they
# contain one or more values, and "falsy" if they are empty.
>>> placeholders = ["spam", "ham", "eggs", "green_spam", "green_ham", "green_eggs"]
>>> while placeholders:
... print(placeholders.pop(0))
...
'spam'
'ham'
'eggs'
'green_spam'
'green_ham'
'green_eggs'
Pythonの基本的なfor loopは、_for each_と呼ぶほうが正確です。任意の反復可能なオブジェクトの値を順にたどり、next()を呼んでも値が返されなくなった時点で終了します。
>>> word_list = ["bird", "chicken", "barrel", "bongo"]
>>> for word in word_list:
... if word.startswith("b"):
... print(f"{word.title()} starts with a B.")
... else:
... print(f"{word.title()} doesn't start with a B.")
...
'Bird starts with a B.'
'Chicken doesn\'t start with a B.'
'Barrel starts with a B.'
'Bongo starts with a B.'
特定のiterableが与えられていないときは、特別なrange()シーケンスがループのカウンターとして使われます。
range()には、シーケンスをstopする位置を示すintが必要で、任意でstartとstepの入力を受け取ることもできます。
startの数値が指定されなければ、シーケンスは0から始まります。
range()オブジェクトは遅延評価です(値は必要なときに生成されます)。また、共通のシーケンス操作をすべてサポートし、指定したシーケンスがどれだけ長くても、一定量のメモリしか使いません。
# Here we use range to produce some numbers, rather than creating a list of them in memory.
# The values will start with 1 and stop *before* 7
>>> for number in range(1, 7):
... if number % 2 == 0:
... print(f"{number} is even.")
... else:
... print(f"{number} is odd.")
'1 is odd.'
'2 is even.'
'3 is odd.'
'4 is even.'
'5 is odd.'
'6 is even.'
# range() can also take a *step* parameter.
# Here we use range to produce only the "odd" numbers, starting with 3 and stopping *before* 15.
>>> for number in range(3, 15, 2):
... if number % 2 == 0:
... print(f"{number} is even.")
... else:
... print(f"{number} is odd.")
...
'3 is odd.'
'5 is odd.'
'7 is odd.'
'9 is odd.'
'11 is odd.'
'13 is odd.'
値とそのインデックスの両方が必要なときは、組み込みのenumerate(<iterable>)が(index, value)のペアを返します。
>>> word_list = ["bird", "chicken", "barrel", "apple"]
# *index* and *word* are the loop variables.
# Loop variables can be any valid python name.
>>> for index, word in enumerate(word_list):
... if word.startswith("b"):
... print(f"{word.title()} (at index {index}) starts with a B.")
... else:
... print(f"{word.title()} (at index {index}) doesn't start with a B.")
...
'Bird (at index 0) starts with a B.'
'Chicken (at index 1) doesn\'t start with a B.'
'Barrel (at index 2) starts with a B.'
'Apple (at index 3) doesn\'t start with a B.'
# The same method can be used as a "lookup" for pairing items between two lists.
# Of course, if the lengths or indexes don't line up, this doesn't work.
>>> word_list = ["cat", "chicken", "barrel", "apple", "spinach"]
>>> category_list = ["mammal", "bird", "thing", "fruit", "vegetable"]
>>> for index, word in enumerate(word_list):
... print(f"{word.title()} is in category: {category_list[index]}.")
...
'Cat is in category: mammal.'
'Chicken is in category: bird.'
'Barrel is in category: thing.'
'Apple is in category: fruit.'
'Spinach is in category: vegetable.'
continueキーワードを使うと、次の繰り返しまでスキップできます。
word_list = ["bird", "chicken", "barrel", "bongo", "sliver", "apple", "bear"]
# This will skip *bird*, at index 0
for index, word in enumerate(word_list):
if index == 0:
continue
if word.startswith("b"):
print(f"{word.title()} (at index {index}) starts with a b.")
'Barrel (at index 2) starts with a b.'
'Bongo (at index 3) starts with a b.'
'Bear (at index 6) starts with a b.'
break(多くのC系言語と同じです)キーワードを使うと、繰り返しを止めて、最も内側のloopから「抜ける」ことができます。
>>> word_list = ["bird", "chicken", "barrel", "bongo", "sliver", "apple"]
>>> for index, word in enumerate(word_list):
... if word.startswith("b"):
... print(f"{word.title()} (at index {index}) starts with a B.")
... elif word == "sliver":
... break
... else:
... print(f"{word.title()} doesn't start with a B.")
... print("loop broken.")
...
'Bird (at index 0) starts with a B.'
'Chicken doesn\'t start with a B.'
'Barrel (at index 2) starts with a B.'
'Bongo (at index 3) starts with a B.'
'loop broken.'
学生の試験を採点するティーチングアシスタントです。 成績を手作業で管理するのは、面倒なうえに間違えやすくなってきました。 そこで、クラスの成績を数えたり計算したりする関数をいくつか組み合わせて、作業をもう少し面白くしてみることにしました。
試験の問題では「部分点」を与えることはできますが、試験全体の点数はintでなければなりません。
そのため、クラスの点数を扱う前に、まず成績を一つひとつ見て、floatの点数をintに変換する必要があります。
幸いなことに、Pythonには組み込みのround()関数があります。
student_scoresのlistを受け取るround_scores(student_scores)関数を作成しましょう。
この関数は、入力のlistを_消費_し、すべての点数をintに変換した新しいリストをreturnする必要があります。
結果のlistに含まれる点数の順序は重要ではありません。
>>> student_scores = [90.33, 40.5, 55.44, 70.05, 30.55, 25.45, 80.45, 95.3, 38.7, 40.3]
>>> round_scores(student_scores)
...
[40, 39, 95, 80, 25, 31, 70, 55, 40, 90]
試験を採点していると、思っていたほど成績が伸びていない学生がいることに気づきました。 しかし、気を取られて、その学生が_何人_いたのかを正確に記録するのを忘れてしまいました。
student_scoresのlistを受け取るcount_failed_students(student_scores)関数を作成しましょう。
この関数は、合格点に達していない学生の数を数え、その数を整数として返す必要があります。
試験で合格するには、40より大きい点数が必要です。
>>> count_failed_students(student_scores=[90,40,55,70,30,25,80,95,38,40])
5
担当している先生は、この試験で「ベスト」な成績を収めた学生のグループを見つけたいと考えています。 何をもって「ベスト」とするかは変動するので、現在のしきい値以上の点数を見つける必要があります。
student_scores(成績のlist)とthreshold(「最高点」のしきい値)を引数に取るabove_threshold(student_scores, threshold)関数を作成しましょう。
この関数は、thresholdに対して>=であるすべての点数のlistを返す必要があります。
>>> above_threshold(student_scores=[90,40,55,70,30,68,70,75,83,96], threshold=75)
[90,75,83,96]
担当している先生は、数値の点数だけでなくアルファベットの成績も付けたいと考えています。 学生が試験で100点を取ることはほとんどないため、「アルファベット成績」の下限のしきい値は、達成された最高点をもとに計算し、最高点と不合格のしきい値である**<= 40**の間を均等に割り振ります。
試験の「最高点」を引数に取り、各「アメリカ式」の成績区分(["D", "C", "B", "A"])の下限のしきい値のlistを返すletter_grades(highest)関数を作成しましょう。
"""Where the highest score is 100, and failing is <= 40.
"F" <= 40
41 <= "D" <= 55
56 <= "C" <= 70
71 <= "B" <= 85
86 <= "A" <= 100
"""
>>> letter_grades(highest=100)
[41, 56, 71, 86]
"""Where the highest score is 88, and failing is <= 40.
"F" <= 40
41 <= "D" <= 52
53 <= "C" <= 64
65 <= "B" <= 76
77 <= "A" <= 88
"""
>>> letter_grades(highest=88)
[41, 53, 65, 77]
試験の点数を降順に並べた配列と、その点数に合わせて降順に並べた学生名の配列があります。 各学生の名前と試験の点数を対応させ、クラス全体の順位を出力したいと考えています。
student_scoresとstudent_namesを引数に持つstudent_ranking(student_scores, student_names)関数を作成しましょう。
student_namesのlistに含まれる各学生の名前を、student_scoresのlistの点数と対応させます。
それぞれの引数のlistは、点数が高い学生から低い学生の順に並んでいるものとします。
この関数は、<rank>. <student name>: <student score>という形式の文字列のlistを返す必要があります。
>>> student_scores = [100, 99, 90, 84, 66, 53, 47]
>>> student_names = ['Joci', 'Sara','Kora','Jan','John','Bern', 'Fred']
>>> student_ranking(student_scores, student_names)
...
['1. Joci: 100', '2. Sara: 99', '3. Kora: 90', '4. Jan: 84', '5. John: 66', '6. Bern: 53', '7. Fred: 47']
試験で「満点」の100点を取ることはまれですが、少なくとも1人の学生が達成したかどうかを知るのは興味深いことです。
student_infoを引数に持つperfect_score(student_info)関数を作成しましょう。
student_infoは、各学生の名前と点数を含むリストからなるlistです: [["Charles", 90], ["Tony", 80]]。
この関数は、試験で100点を取った学生の_最初の_[<name>, <score>]ペアをreturnする必要があります。
student_infoの中に100点が見つからなかった場合は、空のリスト[]を返す必要があります。
>>> perfect_score(student_info=[["Charles", 90], ["Tony", 80], ["Alex", 100]])
["Alex", 100]
>>> perfect_score(student_info=[["Charles", 90], ["Tony", 80]])
[]