Python AtCoder入門 第5講 リストの基礎と操作

>100 Views

September 19, 26

スライド概要

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

ダウンロード

関連スライド

各ページのテキスト
1.

Python AtCoder入門 第5講 リストの基礎と操作 ここから 第2部「データをまとめて扱う」 に入ります。 B問題では、 N 個のデータがまとめて与えられるのが当たり前です。 1

2.

今回のテーマ そこで必要になるのが リスト です。 リストは、 たくさんの値を1つの変数にまとめて入れておく箱 です。 2

3.

この講のゴール この講では、リストを正面から扱います。 作成とアクセス 長さとインデックス スライス 追加と削除 集計関数 コピーの罠 3

4.

コードファイル名の方針 この講でも、コード例ごとにファイル名を付けます。 list_basic.py slice.py append_pop.py aggregate.py copy_trap.py answer_5_1.py 4

5.

5-1 リストの基本 リストは角括弧 [ ] で作ります。 A = [3, 1, 4, 1, 5] 複数の値を1つの変数にまとめられます。 5

6.

インデックスでアクセスする 個々の要素には、インデックスでアクセスします。 A = [3, 1, 4, 1, 5] print(A[0]) print(A[2]) 1番目の要素は A[0] です。 6

7.

list_access.py A = [3, 1, 4, 1, 5] print(A[0]) print(A[2]) 出力: 3 4 7

8.

インデックスは0から始まる A = [3, 1, 4, 1, 5] は3 A[1] は 1 A[2] は 4 Pythonでは番号を0から数えます。 A[0] 8

9.

長さを調べる 要素の個数は len() で取れます。 A = [3, 1, 4, 1, 5] print(len(A)) 出力: 5 9

10.

最後のインデックス 要素が5個なら、使えるインデックスは、 0, 1, 2, 3, 4 です。 最後のインデックスは、 len(A) - 1 10

11.

IndexError A = [3, 1, 4, 1, 5] print(A[5]) これはエラーになります。 IndexError 要素が5個でも、 A[5] は存在しません。 11

12.

負のインデックス Pythonでは、後ろから数えることもできます。 A = [3, 1, 4, 1, 5] print(A[-1]) print(A[-2]) A[-1] は最後の要素です。 12

13.

negative_index.py A = [3, 1, 4, 1, 5] print(A[-1]) print(A[-2]) 出力: 5 1 13

14.

値の変更 リストは、中身を書き換えられます。 A = [3, 1, 4, 1, 5] A[0] = 100 print(A) 出力: [100, 1, 4, 1, 5] 14

15.

リストの出力 A = [3, 1, 4, 1, 5] print(A) 出力: [3, 1, 4, 1, 5] これはデバッグには便利ですが、AtCoderの答えとしては多くの場合WAです。 15

16.

空白区切りで出力する 答えとして空白区切りで並べるなら、 print(*A) を使います。 A = [3, 1, 4, 1, 5] print(*A) 出力: 3 1 4 1 5 16

17.

list_basic.py # Create a list A = [3, 1, 4, 1, 5] # Access by index print(A[0], A[2]) # Length and the last element print(len(A), A[-1]) # Modify an element A[1] = 99 print(*A) 17

18.

list_basic.py の出力 3 4 5 5 3 99 4 1 5 print(*A) により、空白区切りで出力されています。 18

19.

5-2 スライス スライスは、リストの一部を切り出して、 新しいリストとして取り出す 書き方です。 A = [0, 1, 2, 3, 4, 5] print(A[2:5]) 19

20.

A[i:j] A[i:j] は、インデックス i 以上 j 未満を取り出します。 A = [0, 1, 2, 3, 4, 5] print(A[2:5]) 出力: [2, 3, 4] 20

21.

スライスの形 書き方 A[i:j] A[i:] A[:j] A[:] A[::-1] 意味 i以上j未満 iから最後まで 最初からj未満 全部 逆順 例 A[2:5] A[3:] A[:3] A[:] A[::-1] 21

22.

A[::-1] A = [0, 1, 2, 3, 4, 5] print(A[::-1]) 出力: [5, 4, 3, 2, 1, 0] 逆順にしたいときの定石です。 22

23.

スライスは新しいリストを作る 重要な性質です。 スライスは、元のリストを変えずに新しいリストを作ります。 この性質は、後で扱う「コピーの罠」で重要になります。 23

24.

slice.py A = [0, 1, 2, 3, 4, 5] # Extract a range print(*A[2:5]) # From index 3 to the end print(*A[3:]) # Reverse print(*A[::-1]) # The original list is unchanged print(*A) 24

25.

slice.py の出力 2 3 4 3 4 5 5 4 3 2 1 0 0 1 2 3 4 5 最後の行に注目してください。 A 自身は変わっていません。 25

26.

5-3 要素の追加・削除 リストには、あとから要素を追加したり削除したりできます。 ここでは、よく使うメソッドを確認します。 26

27.

追加のメソッド メソッド A.append(x) A.insert(i, x) 意味 末尾に x を追加する インデックス i の位置に x を挿入する 競技プログラミングでは、 append が特によく出ます。 27

28.

append A = [1, 2, 3] A.append(4) print(A) 出力: [1, 2, 3, 4] 末尾に追加します。 28

29.

appendの定番パターン 空のリストを用意して、ループの中で追加します。 A = [] for i in range(5): A.append(i * i) print(*A) 出力: 0 1 4 9 16 29

30.

削除のメソッド メソッド A.pop() A.pop(i) A.remove(x) 意味 末尾の要素を取り除いて返す インデックス i の要素を取り除いて返す 値が x である最初の要素を取り除く 30

31.

pop A = [3, 1, 4, 1, 5] x = A.pop() print(x) print(A) 出力: 5 [3, 1, 4, 1] 31

32.

remove A = [3, 1, 4, 1, 5] A.remove(1) print(A) 出力: [3, 4, 1, 5] 最初に見つかった 1 だけが消えます。 32

33.

removeの注意 には注意点があります。 消えるのは最初に見つかった1個だけ その値が存在しないと ValueError になる 「あれば消す」なら、事前に存在確認が必要です。 remove 33

34.

append_pop.py # Build a list with append A = [] for i in range(1, 6): A.append(i * 10) print(*A) # Remove the last element last = A.pop() print(last) print(*A) # Insert at the front A.insert(0, 5) print(*A) 34

35.

append_pop.py の出力 10 20 30 40 50 50 10 20 30 40 5 10 20 30 40 append 、 pop 、 insert の動きを確認しましょう。 35

36.

5-4 集計関数と存在判定 リストには、便利な関数やメソッドがたくさんあります。 第4講では for で自力で書いた処理も、1行で済むことがあります。 36

37.

集計関数 書き方 len(A) sum(A) max(A) min(A) A.count(x) 意味 要素数 合計 最大値 最小値 x が何個あるか 37

38.

aggregate_basic.py A = [3, 1, 4, 1, 5] print(len(A), sum(A), max(A), min(A)) print(A.count(1)) 出力: 5 14 5 1 2 38

39.

空のリストに注意 max(A) min(A) は、空のリストに使うと ValueError になります。 要素が0個になり得る場面では注意してください。 39

40.

存在判定 in その値がリストに含まれているかは、 in で調べられます。 A = [3, 1, 4, 1, 5] print(4 in A) print(9 in A) 40

41.

in_basic.py A = [3, 1, 4, 1, 5] print(4 in A) print(9 in A) 出力: True False 存在するかだけを知りたいなら、 in が簡潔です。 41

42.

Yes / No にする if X in A: print("Yes") else: print("No") 第4講のフラグパターンを、1行の条件で書けます。 42

43.

inの注意 リストの in は、先頭から順に全部調べます。 そのため、巨大なリストに対してループの中で何度も使うと遅くなります。 この話は第10講で扱います。 43

44.

index その値が何番目にあるかは、 index() で取れます。 A = [3, 1, 4, 1, 5] print(A.index(4)) print(A.index(1)) index() は、最初に見つかった位置だけを返します。 44

45.

aggregate.py # Read N and the list of N integers N = int(input()) A = list(map(int, input().split())) # Aggregate print(len(A), sum(A), max(A), min(A)) 入力例: 5 3 1 4 1 5 出力例: 5 14 5 1 45

46.

max_position.py # Read N and the list of N integers N = int(input()) A = list(map(int, input().split())) # Find the maximum and its 1-indexed position best = max(A) position = A.index(best) + 1 print(position, best) 46

47.

max_position.py の実行例 入力例: 5 3 1 5 1 5 出力例: 3 5 最大値 5 は複数ありますが、最初の位置が返ります。 47

48.

+1を忘れない は0始まりの位置を返します。 問題文が1始まりなら、 index() position = A.index(best) + 1 のように + 1 が必要です。 48

49.

5-5 リストのコピーの罠 この節は短いですが、本講で最も重要です。 ここを知らないと、原因のわからないバグに何時間も悩むことがあります。 49

50.

b = a はコピーではない まず、次のコードを見てください。 a = [1, 2, 3] b = a b[0] = 100 print(a) b を変えたのに、 a も変わります。 50

51.

copy_trap.py a = [1, 2, 3] b = a b[0] = 100 print(a) print(b) 出力: [100, 2, 3] [100, 2, 3] 51

52.

同じリストに別名を付けている b = a は、中身を複製していません。 同じリストに別の名前を付けているだけ です。 片方を変更すると、もう片方も変わります。 52

53.

正しくコピーする 独立した別のリストが欲しいときは、次のいずれかを使います。 書き方 b = a[:] b = list(a) b = a.copy() 説明 スライスで全体を取り出す リストを作り直す コピー用のメソッド 53

54.

copy_ok.py a = [1, 2, 3] b = a[:] b[0] = 100 print(a) print(b) 出力: [1, 2, 3] [100, 2, 3] 今度は a が変わっていません。 54

55.

copy_trap_compare.py # Case 1: b = a a = [1, 2, 3] b = a b[0] = 100 print(*a) print(*b) # Case 2: b = a[:] a = [1, 2, 3] b = a[:] b[0] = 100 print(*a) print(*b) 55

56.

copy_trap_compare.py の出力 100 2 3 100 2 3 1 2 3 100 2 3 上の2行は同じ、下の2行は違います。 この差がすべてです。 56

57.

元を残したまま操作したいとき コピーの罠は、 元のリストを残したまま、加工したものも欲しい という場面で問題になります。 例: 元の順序も出力する 並べ替えた結果も出力する 2倍したリストも作る 57

58.

double_copy.py # Read N and the list of N integers N = int(input()) A = list(map(int, input().split())) # Make an independent copy and double every element B = A[:] for i in range(N): B[i] = B[i] * 2 # The original list is still intact print(*A) print(*B) 58

59.

double_copy.py の実行例 入力例: 5 3 1 4 1 5 出力例: 3 1 4 1 5 6 2 8 2 10 A は元のまま残っています。 59

60.

章末まとめ リストは [ ] で作ります。 インデックスは0始まりです。 A[0] が1番目の要素です。 最後のインデックスは len(A) - 1 です。 60

61.

章末まとめ:出力 リストをそのまま出すと、角括弧が付きます。 print(A) 答えとして並べるなら、 print(*A) を使います。 61

62.

章末まとめ:スライス A[i:j] は、 i 以上 j 未満です。 A[::-1] で逆順にできます。 スライスは元のリストを変えず、新しいリストを作ります。 62

63.

章末まとめ:集計 よく使う集計は次の通りです。 len(A) sum(A) max(A) min(A) A.count(x) 存在判定は X in A です。 63

64.

章末まとめ:コピー b = a はコピーではありません。 同じリストに別名を付けているだけです。 独立したコピーが欲しいなら、 b = a[:] を使います。 64

65.

練習問題 5-1 合計・最大・最小 個の整数 A_1, A_2, ..., A_N が与えられます。 合計、最大値、最小値を、この順に空白区切りで1行に出力してください。 N 65

66.

練習問題 5-1:入力と出力 入力: N A_1 A_2 ... A_N 入力例: 5 30 10 40 10 50 出力例: 140 50 10 66

67.

answer_5_1.py # Read N and the list of N integers N = int(input()) A = list(map(int, input().split())) # Print the sum, the maximum, and the minimum print(sum(A), max(A), min(A)) 集計関数をそのまま使います。 67

68.

練習問題 5-2 逆順に出力 個の整数 A_1, A_2, ..., A_N が与えられます。 これらを逆順に並べ替えて、空白区切りで1行に出力してください。 N 68

69.

練習問題 5-2:入力と出力 入力: N A_1 A_2 ... A_N 入力例: 5 3 1 4 1 5 出力例: 5 1 4 1 3 69

70.

answer_5_2.py # Read N and the list of N integers N = int(input()) A = list(map(int, input().split())) # Print the list in reverse order print(*A[::-1]) print(A[::-1]) ではなく、 print(*A[::-1]) です。 70

71.

練習問題 5-3 元のリストと2倍したリスト 個の整数 A_1, A_2, ..., A_N が与えられます。 1行目に元の数列を出力します。 2行目に各要素を2倍した数列を出力します。 N 71

72.

練習問題 5-3:入力と出力 入力: N A_1 A_2 ... A_N 入力例: 4 2 7 1 8 出力例: 2 7 1 8 4 14 2 16 72

73.

answer_5_3.py # Read N and the list of N integers N = int(input()) A = list(map(int, input().split())) # Make an independent copy and double every element B = A[:] for i in range(N): B[i] = B[i] * 2 print(*A) print(*B) 73

74.

appendで新しく作る方法 # Read N and the list of N integers N = int(input()) A = list(map(int, input().split())) # Build a new list without touching A B = [] for x in A: B.append(x * 2) print(*A) print(*B) 74

75.

第5講まとめ この講では、 リストの基礎と操作 を学びました。 B問題では、リストを使ってN個のデータをまとめて処理する場面が一気に増えます。 75

76.

次回予告 次の第6講では、 タプルと内包表記 を扱います。 B = [] と append で組み立てたリストが、たった1行で書けるようになります。 76