インデックスやスライスを使って、リスト(配列)の要素を取得、削除、変更する方法を紹介する。
この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。
* 本稿は2020年12月8日に公開された記事をPython 3.12.1で動作確認したものです(確認日:2024年1月8日)。
mylist = list(range(10))
print(mylist) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# インデックスによるアクセス
n = mylist[1] # 正数は先頭からのインデックス。先頭の要素のインデックスが0
print(n) # 1
n = mylist[-2] # 負数は末尾からのインデックス。末尾の要素のインデックスが-1
print(n) # 8
# スライスによるアクセス
mylist = list(range(10))
s = mylist[0:5] # 0〜4番目の5要素を取り出す
print(s) # [0, 1, 2, 3, 4]
Pythonでは、他の言語における配列はリストとして実装されている。その要素には、インデックスやスライスといった機構を通じてアクセスできる。その基本は次のようになっている。
スライスの場合、upper_boundに指定するインデックス位置にある要素はスライスの要素には含まれず、その1つ手前の要素までがスライスに含まれることには注意が必要だ。詳細については「インデックスによるアクセス」および「スライスによるアクセス」を参照されたい。
mylist = list(range(10))
# インデックスを使った要素の取り出し
n = mylist[7]
print(n) # 7
# インデックスを使った要素の削除
del mylist[4]
print(mylist) # [0, 1, 2, 3, 5, 6, 7, 8, 9]
# インデックスを使った要素の変更
mylist[-1] = 90
print(mylist) # [0, 1, 2, 3, 5, 6, 7, 8, 90]
インデックスを使って、要素を取り出すときにはその値が必要な場所で、「リスト[取り出したい要素のインデックス]」と記述する。特定の要素の値を削除するにはdel文を使用して「del リスト[削除したい要素のインデックス]」のように書く。値を変更するには、代入文で「リスト[値を変更したい要素のインデックス] = 新しい値」のようにする。詳細については「インデックスによるアクセス」を参照のこと。
# スライスによるアクセス
mylist = list(range(10))
s = mylist[:] # 全要素を取り出す
print(s) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
s = mylist[5:] # 5番目以降の全要素を取り出す
print(s) # [5, 6, 7, 8, 9]
s = mylist[:5] # 0〜4番目の5要素を取り出す
print(s) # [0, 1, 2, 3, 4]
s = mylist[0:10:2] # 0、2、4、6、8番目の要素を取り出す
print(s) # [0, 2, 4, 6, 8]
s = mylist[::2] # 同上
print(s) # [0, 2, 4, 6, 8]
s = mylist[-4:] # -4番目から末尾までの全要素を取り出す
print(s) # [6, 7, 8, 9]
s = mylist[-1:-9:-1] # リスト末尾から逆順に要素を取り出す
print(s) # [9, 8, 7, 6, 5, 4, 3, 2]
# スライスを使った要素の削除
mylist = list(range(10))
del mylist[3:5] # 3番目と4番目の要素を削除
print(mylist) # [0, 1, 2, 5, 6, 7, 8, 9]
del mylist[0::2] # 上の削除結果から、0、2、4、6番目の要素を削除
print(mylist) # [1, 5, 7, 9]
mylist[0:2] = [] # 上の削除結果から先頭の2要素を削除
print(mylist) # [7, 9]
# スライスを使った要素の変更
mylist = list(range(10))
mylist[1:3] = [10, 20] # スライスの先頭と末尾を指定して要素を変更
print(mylist) # [0, 10, 20, 3, 4, 5, 6, 7, 8, 9]
mylist[1:3] = [1, 1.5, 2] # この場合はスライスと新しい値の要素数が異なってもOK
print(mylist) # [0, 1, 1.5, 2, 3, 4, 5, 6, 7, 8, 9]
mylist = list(range(10))
mylist[1::2] = [10, 30, 50, 70, 90] # 先頭/末尾/増分を指定して要素を変更
print(mylist) # [0, 10, 2, 30, 4, 50, 6, 70, 8, 90]
mylist[0::2] = [0.0, 2.0, 4.0] # ValueError:このときには同じ要素数でないとダメ
スライスを使って、リストから特定の範囲の要素を取り出すには、それらが必要となる部分で「リスト[開始位置:終了位置:増分]」のように記述する。特定の範囲に含まれる要素を削除するにはdel文を使って「del リスト[開始位置:終了位置:増分]」と書くか、代入文で「リスト[開始位置:終了位置:増分] = []」のようにスライスに空のリストを代入する。スライスに含まれる要素を変更するには、代入文で「リスト[開始位置:終了位置:増分] = [新しい値を含んだリスト]」のようにする。ただし、注意点がある。詳細については「スライスによるアクセス」を参照してほしい。
Pythonのリスト(配列)に格納される要素にアクセスしたり利用したりするには幾つかの方法がある。その中でも基本的なのが、本稿で紹介するインデックスやスライスを用いて、要素を取り出したり、変更したりすることだ。以下では、まずインデックスによる要素の取得、削除、変更について見ていこう。
インデックスによるアクセスでは、角かっこ「[]」内にアクセスしたい要素のインデックスを指定するだけだ(0始まり)。以下に例を示す。なお、以下では数値のみを要素とするリスト(整数リスト、整数配列)を例とする。
mylist = list(range(10)) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# インデックスによる要素の読み出し
n = mylist[7] # 7番目の要素の取得(0始まり)
print(n) # 7
n = mylist[10] # IndexError:要素がないインデックスにアクセスすると例外
範囲外へのアクセスは上のコード例に示した通り、IndexError例外となる。
全ての要素に順次アクセスして、その値を使うために、次のようなコードを書きたくなるかもしれない。
for idx in range(len(mylist)):
print(mylist[idx])
このコードでは、リストmylistの要素数をlen関数で取得して、range関数を用いてその数だけループを行っている。だが、Pythonではリスト(配列)の値を使用するだけであれば、上のようなコードではなく、以下のようなコードとするのが一般的だ。
for num in mylist:
print(num)
こちらのコードでは、リストmylistに格納されている要素をループ変数numに列挙して、それをループ内で利用している。この方がコードはシンプルで見やすくなるだろう。
インデックスには負値も指定できる。このとき、-1は末尾の要素を表し、「-len(リスト)」が先頭の要素を表す。
n = mylist[-1]
print(n) # 9
n = mylist[-len(mylist)]
print(n) # 0
特定のインデックスの要素を削除するには、del文で「del リスト[インデックス]」と記述する。
idx = mylist.index(3) # mylist中で要素3のインデックスを検索
del mylist[idx] # 要素3を削除
print(mylist) # [0, 1, 2, 4, 5, 6, 7, 8, 9]
リストのpopメソッドにインデックスを渡しても同様な処理は可能だ。
インデックスを用いて、要素の値を変更するには、代入文で「リスト[インデックス] = 新しい値」と記述する。
mylist = list(range(10))
mylist[9] = 90
print(mylist) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 90]
なお、for文を用いて、リストの要素を変更したいときには、以下のようなコードだとうまくいかない。
mylist = list(range(10))
print(mylist) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
for num in mylist:
num *= 2 # 各要素の値を2倍したつもりだが……
print(mylist) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] # 元のリストに変わりはない
この例ではループのたびに、ループ変数numが、対応するインデックスにあるmylistの要素を参照するようになるが、その後の代入(num *= 2)により、numはmylistの要素とは別の値を参照するようになるからだ。forループを使って、リストの要素を変更したいのであれば、先ほどはお勧めしなかったインデックスをループ変数に代入していく方法をとる。
for idx in range(len(mylist)):
mylist[idx] *= 2
print(mylist) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
# 参考:mylist = list(map(lambda x: x * 2, mylist))
上記コードの最終行のコメントも参考にされたい(map関数を用いて、リストの各要素の値を2倍した新しいリストを作成している)。
Pythonのリスト(配列)では「ここからここまでの要素」を指定できる。これをスライスと呼ぶ。スライスはインデックスと同様に角かっこ「[]」で囲んで「[lower_bound:upper_bound:stride]」のように指定する。lower_boundはスライスがリストのどの要素から始まるかを、upper_boundはスライスがリストのどの要素(の手前の要素)で終わるかを、strideは増分を指定する。
スライスの指定では、lower_bound/upper_bound/strideはいずれも省略可能だが、lower_boundに続くコロン「:」だけは必須である。lower_bound/strideを省略した場合、lower_boundの値は「0」と、strideの値は「1」と見なされると考えられる。また、upper_boundを省略したときには、リストの末尾までが範囲に含められるような指定を行ったものと考えられる。
これらから、スライスを表す最低限の表記は「[:]」となり、その場合は「[0:末尾まで含む:1]」を指定したものと考えられる(先頭から末尾までの全要素。「末尾まで含む」までは便宜的な表現)。
スライスに含まれる要素のインデックスをidxとすると、「idx=lower_bound+stride×i」(iは0以上の整数)として計算でき、その範囲は「lower_bound ≦ idx < upper_bound」(strideが正値の場合)もしくは「lower_bound ≧ idx > upper_bound」(strideが負値の場合)となる。いずれにしても、upper_boundに指定するインデックスの値は、スライスには含まれないことに注意。
以下にスライスを用いてリストの要素を取得する例を幾つか示す(コメントではlower_boundを「lower」と、upper_boundを「upper」と表記する)。
mylist = list(range(10)) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
s = mylist[:] # lower=0、upper=末尾まで、stride=1:全要素
print(s) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
s = mylist[0:5] # lower=0、upper=5、stride=1:0〜4番目までの5要素
print(s) # [0, 1, 2, 3, 4]
s = mylist[5:] # lower=5、upper=末尾まで、stride=1:5番目から末尾までの要素
print(s) # [5, 6, 7, 8, 9]
s = mylist[:5] # lower=0、upper=5、stride=1:0〜4番目までの5要素
print(s) # [0, 1, 2, 3, 4]
s = mylist[0:10:2] # lower=0、upper=10、stride=2:0、2、4、6、8番目の要素
print(s) # [0, 2, 4, 6, 8]
s = mylist[::2] # lower=0、upper=末尾まで、stride=2:0、2、4、6、8番目の要素
print(s) # [0, 2, 4, 6, 8]
最後の例のように、スライスの指定ではlower_boundもupper_boundも(もちろん、strideも)省略できることは覚えておこう。この例では、stride=2としているので、その上のコード例と同じスライスが得られている。
Copyright© Digital Advantage Corp. All Rights Reserved.