コンピュータ演習II 第09回 整数以外のリスト、range の応用、入れ替え¶
第05回でリスト、第06回で繰り返し(for 文)を学びました。今回は、その2つを組み合わせて、次の3つを学びます。
- 整数以外のリスト(文字列を要素にしたリスト)
- range の応用(とびとびに進む「ステップ」、後ろから前へ進む「逆順」)
- 要素の入れ替え(swap)(リストの要素を交換し、並び替える)
1. 整数以外のリスト¶
1.1 文字列のリスト¶
リストの要素は、整数だけでなく 文字列 でもかまいません。次の fruits は、5 つの文字列を要素に持つリストです。
アクセスの仕方は、整数のリストとまったく同じです。fruits[0] で先頭の要素("apple")が取り出せますし、len(fruits) で要素の個数(5)が分かります。
fruits = ["apple", "banana", "cherry", "melon", "lemon"] # 要素が文字列のリスト
print(fruits[0]) # 先頭の要素 -> apple
print(fruits[2]) # インデックス 2(3 番目)の要素 -> cherry
print(len(fruits)) # 要素の個数 -> 5
1.2 文字列リストを for 文で処理する¶
整数のリストと同じように、for 文と range(0, len(fruits)) で全要素を順に処理できます。要素が文字列でも、取り出し方(fruits[i])や繰り返し方は、整数のリストとまったく同じです。
fruits = ["apple", "banana", "cherry", "melon", "lemon"]
# i は 0, 1, 2, 3, 4 と変わり、全要素を順に取り出す
for i in range(0, len(fruits)):
print(fruits[i]) # i 番目の要素を出力
1.3 文字列も「文字の並び」として扱える¶
実は、文字列もリストと同じように「文字が並んだもの」 として扱えます。word[0] で先頭の文字、word[4] で5 番目の文字が取り出せます。インデックスが 0 から始まるところも、リストとまったく同じです。
また、len() は、リストの要素数だけでなく、文字列の文字数 を数えるのにも使えます(len("apple") は 5)。
for 文と組み合わせれば、文字列の 1 文字ずつ を順に処理できます。
word = "hello"
print(word[0]) # 先頭の文字 -> h
print(word[4]) # インデックス 4 の文字 -> o
print(len(word)) # 文字数 -> 5
# for で 1 文字ずつ取り出す(リストとまったく同じ書き方)
for i in range(0, len(word)):
print(i, word[i]) # インデックスi と i 番目の文字を出力
1.4 後ろから数えるインデックス(負のインデックス)¶
インデックスに 負の数 を使うと、後ろから 数えられます。numbers[-1] はいちばん後ろ(末尾)の要素、numbers[-2] はその1 つ前です。
これまで末尾の要素は numbers[len(numbers) - 1] と書いてきましたが、numbers[-1] ならもっと短く書けます。文字列でも同じように使えます(word[-1] で最後の文字)。
numbers = [10, 20, 30, 40, 50]
print(numbers[-1]) # いちばん後ろ(末尾) -> 50
print(numbers[-2]) # 後ろから 2 番目 -> 40
# これまでの len を使った書き方と同じ結果になる
print(numbers[len(numbers) - 1]) # -> 50 (numbers[-1] と同じ)
word = "hello"
print(word[-1]) # 最後の文字 -> o
2. range の応用(3 つ目の引数)¶
これまでは range(開始, 終了) の形で、1 ずつ増える繰り返しを作ってきました。実は range には 3 つ目の引数 があり、range(開始, 終了, ステップ) と書くと、増える量(ステップ)を変えられます。
2.1 とびとびに進む(ステップ)¶
ステップに 2 を指定すると、2 ずつ増えます。range(0, 11, 2) は 0, 2, 4, 6, 8, 10 です。終わりの値 11 は 含まない(手前で止まる)のは、これまでと同じです。
# range の 3 つ目の数(ここでは 2)が「いくつずつ増えるか」(ステップ)を表す
for even in range(0, 11, 2): # 0 から 2 ずつ、11 の手前まで
print(even) # 0, 2, 4, 6, 8, 10 が順に出る
リストと組み合わせると、偶数番目(インデックス 0, 2, 4, ...)の要素だけ を処理する、といったことができます。
numbers = [10, 20, 30, 40, 50]
# インデックスを 2 ずつ進めると、偶数番目(0, 2, 4)の要素だけを取り出せる
for even in range(0, len(numbers), 2): # even = 0, 2, 4
print(numbers[even]) # 偶数番目の要素 -> 10, 30, 50
2.2 逆順(後ろから前へ)¶
ステップに 負の数 を指定すると、数は 減って いきます。後ろから前へ進みたいときに使います。range(10, -1, -1) は 10, 9, 8, ..., 1, 0 です。
終わりの値は含まないので、0 まで出したいときは、その1 つ先の -1 を終わりに指定します。
# ステップを -1 にすると、数は 1 ずつ減っていく(後ろから前へ進む)
for reverse in range(10, -1, -1): # 10 から始めて、-1 の手前(=0)まで
print(reverse) # 10, 9, 8, ..., 1, 0 が順に出る
リストを 後ろから順に 処理するときは、range(len(numbers) - 1, -1, -1) とします。先頭のインデックスは len(numbers) - 1、最後は 0(その手前の -1 を終わりに指定)です。
numbers = [10, 20, 30, 40, 50]
# 最後のインデックス len(numbers)-1 から 0 まで、後ろ向きにたどる
for reverse in range(len(numbers) - 1, -1, -1): # reverse = 4, 3, 2, 1, 0
print(numbers[reverse]) # 後ろから順に -> 50, 40, 30, 20, 10
3. 入れ替え(swap)¶
3.1 2 つの値の入れ替え(なぜ変数 tmp が必要なのか)¶
2 つの変数 x と y の中身を入れ替えたいとします。しかし、いきなり x = y としてしまうと、x のもとの値が 消えて しまい、あとから取り戻せません。
そこで、片方の値を一時的に別の変数(ここでは tmp と呼びます)へ 逃がして から入れ替えます。
次の3 ステップで行います。
x = 6
y = 1
tmp = 0 # 一時変数、temporary の略でtmp と名付けることが多い
# いきなり x = y とすると、x のもとの値(6)が消えて取り戻せない。
# そこで tmp に片方を逃がしてから、3 ステップで入れ替える。
tmp = x # tmp に x のもとの値(6)を保存しておく
x = y # x に y の値(1)を入れる
y = tmp # y に、保存しておいた 6 を入れる
print(x, y) # 1 6
tmp は temporary(一時的)の略で、値を一時的に置いておくための変数です。ここでは入れ替えのための入れ物として使うので、tmp という名前で十分です。
3.2 リストの隣り合う2 要素の入れ替え¶
同じやり方で、リストの 隣り合う2 つの要素 numbers[i] と numbers[i+1] も入れ替えられます。考え方は変数のときとまったく同じで、tmp に片方を逃がしてから入れ替えます。
numbers = [6, 1, 2, 5, 0]
i = 0 # 入れ替えたい位置(ここでは 0 番目と 1 番目)
# 変数 x, y のときと同じ 3 ステップ。tmp に片方を逃がしてから入れ替える。
tmp = numbers[i] # numbers[0](=6)を tmp に逃がす
numbers[i] = numbers[i + 1] # numbers[0] に numbers[1](=1)を入れる
numbers[i + 1] = tmp # numbers[1] に、逃がしておいた 6 を入れる
print(numbers) # [1, 6, 2, 5, 0]
3.3 条件つきの入れ替え(if と組み合わせる)¶
「隣り合う2 つを比べて、前のほうが大きいときだけ 入れ替える」という処理を考えます。if で大小を判定し、条件が成り立つときだけ入れ替えます。こうすると、隣り合う2 つは必ず 小さい方が前、大きい方が後ろ に並びます。
numbers = [6, 1, 2, 5, 0]
i = 0
# 前(numbers[i])のほうが大きいときだけ入れ替える。
# こうすると、この隣り合う 2 つは必ず「小さい方が前、大きい方が後ろ」になる。
if numbers[i] > numbers[i + 1]:
tmp = numbers[i]
numbers[i] = numbers[i + 1]
numbers[i + 1] = tmp
print(numbers) # [1, 6, 2, 5, 0]
4. 繰り返しを用いた要素の移動¶
3.3 の「条件つき入れ替え」を、先頭のペアから末尾のペアまで順に くり返します。隣り合う numbers[i] と numbers[i+1] を比べ、前のほうが大きければ入れ替える、という処理を先頭から末尾まで行います。
for のインデックスは range(0, len(numbers) - 1) とします。最後のペアは numbers[len(numbers)-2] と numbers[len(numbers)-1] なので、i は len(numbers) - 2 まで動けば十分だからです(range(0, len(numbers)-1) は 0 から len(numbers)-2 まで)。
こうして先頭から末尾まで隣同士を比べていくと、いちばん大きい要素が、いちばん後ろまで運ばれていきます。
numbers = [6, 1, 2, 5, 0]
# 左から順に、隣り合うペア(numbers[i] と numbers[i+1])を比べていく。
# i は 0 から len(numbers)-2 まで(最後のペアは numbers[len-2] と numbers[len-1])。
for i in range(0, len(numbers) - 1): # i = 0, 1, 2, 3
if numbers[i] > numbers[i + 1]: # 前のほうが大きければ
tmp = numbers[i] # tmp を使って入れ替える
numbers[i] = numbers[i + 1]
numbers[i + 1] = tmp
print(numbers) # [1, 2, 5, 0, 6] <- いちばん大きい 6 が後ろへ
この「先頭から末尾までの比較・入れ替え」を 並び終わるまで何度もくり返す と、リスト全体がきれいに並びます。これが 並べ替え(整列) で、第11回でくわしく扱います。今回は、まず この処理を確実に書けるようにしておきましょう。
5. フローチャートで見る¶
今回の課題は、フローチャートを組んで提出します(ツールの使い方は、課題の説明と別紙のクイックリファレンスを参照してください)。ここでは、今回の中心である入れ替え(swap)と、4 章の「繰り返しで隣どうしを比べる処理」が、フローチャートでどう見えるかを確認しておきます。
5.1 配列要素の入れ替え(tmp 経由)¶
入れ替えは、Python と同じ3 ステップ(tmp = numbers[i] → numbers[i] = numbers[i+1] → numbers[i+1] = tmp)を、変数・値のブロックで順に並べるだけです。条件つきにするときは、これらを条件分岐(if)の True 側に入れます。
5.2 繰り返しで隣どうしを比べる流れ¶
4 章の「繰り返しを用いた要素の移動」をフローチャートにすると、下のようになります。繰り返しは for のひし形で作り、中身は Python とまったく同じ for i in range(0, len(numbers) - 1): を書きます。「次あり」の側に「if(numbers[i] > numbers[i+1])→ 入れ替え」を入れると、先頭から末尾まで隣どうしを比べて交換する流れになります。
まとめ¶
- リストの要素は 文字列 でもよい。アクセスや
len()の使い方は整数のリストと同じ。文字列そのものも「文字の並び」 として、word[0]やlen(word)で1 文字ずつ扱える。 - インデックスに 負の数 を使うと 後ろから 数えられる。
numbers[-1]は末尾、numbers[-2]はその1 つ前(numbers[len(numbers)-1]の短い書き方)。 range(開始, 終了, ステップ)の3 つ目の引数で、とびとび(range(0, 11, 2))や 逆順(range(10, -1, -1))の繰り返しが作れる。終わりの値は含まない。- 2 つの値の 入れ替え(swap) は、
tmpに片方を逃がしてから行う。ifと組み合わせると条件つきの入れ替えになる。 - 隣り合うペアを 先頭から末尾まで順に 条件つきで入れ替えると、最大の要素が後ろへ運ばれる。これを何度もくり返すと並べ替え(第11回)になる。