【Pythonスライス】リスト・文字列などのインデックス操作

スライスとは?

スライス表記 とは、文字列、リスト、またはタプルなどのイテラブルオブジェクトの特定範囲をインデックス(位置)によって指定し、それらの要素にアクセスする仕組み(構文)のこと。

構文 [::] と演算子「コロン」

スライス表記の構文は [::] のように、「鉤括弧の中に演算子コロンを1つまたは2つ」で表す。

object[ start : stop : step ]

  • objectは、文字列、リスト、またはタプルなどのイテラブルオブジェクト。
  • start は開始インデックス(位置)を指定。
  • stop は終了インデックス(位置)を指定。
  • step は増分インデックスを指定。
python
Copied!
# 構文サンプル

# リストを初期化
my_list = ['a', 'b', 'c', 'd', 'e', 'f']

print(my_list[1:3])
# ['b', 'c']

print(my_list[1:6:2])
# ['b', 'd', 'f']

インデックスの理解と考え方

インデックスについての考え方は、次のように理解すると良い。

  • インデックスとは文字と文字の間のことを指す
  • 文字列の左端のインデックスは 0 となる
  • n 個の文字列の右端のインデックスは n となる
  • 文字列の右端の一つ前のインデックスは -1 となる

Pythonのオフィシャルサイトからの引用。

スライスの使い方を覚えるよい方法は、インデックスが文字と文字のあいだ (between) を指しており、最初の文字の左端が 0 になっていると考えることです。そうすると、 n 文字からなる文字列中の最後の文字の右端はインデックス n となります。

次のコードは、インデックスの考え方について、文字列、リスト、タプルをもとに分かりやすく表記したもの。

python
Copied!
# インデックスの理解と考え方

# 文字列を定義
my_strg = 'Python'

# リストを定義
my_list = ['a', 'b', 'c', 'd', 'e', 'f']

# タプルを定義
my_tupl = ('a', 'b', 'c', 'd', 'e', 'f')

# my_strg、my_list、my_tuplのインデックス
          +---+---+---+---+---+---+
my_strg = | P | y | t | h | o | n |
          +---+---+---+---+---+---+
my_list = |'a'|'b'|'c'|'d'|'e'|'f'|
          +---+---+---+---+---+---+
my_tupl = |'a'|'b'|'c'|'d'|'e'|'f'|
          +---+---+---+---+---+---+
          0   1   2   3   4   5   6  # 左端(先頭)から 0 で始まる 
         -6  -5  -4  -3  -2  -1      # 右端(末尾)の1つ前から -1 で始まる

スライスの基本的な使い方

スライスを使用するとイテラブルオブジェクトの任意の部分にアクセスできる。

開始と終了のインデックス

リストのようなイテラブルオブジェクトを定義するとインデックスも同時に定義され、スライスでのアクセスが可能となる。

python
Copied!
# リストを定義
lis = ['P', 'y', 't', 'h', 'o', 'n']

# lisのインデックス
      +---+---+---+---+---+---+
lis = |'P'|'y'|'t'|'h'|'o'|'n'|
      +---+---+---+---+---+---+
      0   1   2   3   4   5   6

先頭からのアクセス

[0:3] とすると先頭から3めの要素までにアクセスできる。

[:3] のように開始位置を省略するとインデックスは 0 と同義となる。

python
Copied!
# リストを定義
lis = ['P', 'y', 't', 'h', 'o', 'n']
# スライス[0:3]指定
# 先頭から3つ目の要素まで指定
print(lis[0:3])
print(lis[:3]) # 0は省略できる
# ['P', 'y', 't']
          +---+---+---+
lis[:3] = |'P'|'y'|'t'|
          +---+---+---+
          0   1   2   3

指定位置以降から末尾へのアクセス

[2:] のように stop を省略すると、末尾となる。

この場合、開始位置 2 以降、末尾までとなる。

python
Copied!
lis = ['P', 'y', 't', 'h', 'o', 'n']
# インデックス 2 の位置から末尾まで指定
print(lis[2:6]) # 末尾のインデックスは 6
# ['t', 'h', 'o', 'n']
print(lis[2:])  # 末尾のインデックスを省略
# ['t', 'h', 'o', 'n']
          +---+---+---+---+
lis[2:] = |'t'|'h'|'o'|'n'|
          +---+---+---+---+
          2   3   4   5   6

範囲外のスライス指定は無視される

[2:8] のように stop の位置が要素の総数を超えたとしても、無視され、最後(末尾)までの指定となる。

python
Copied!
lis = ['P', 'y', 't', 'h', 'o', 'n']
# インデックス 8 の位置まで指定
print(lis[2:8])
# ['t', 'h', 'o', 'n']
# たとえ総数より多いインデックスを指定しても無視される

startstop の省略は全要素と同義

[:] のように startstop の両方を省略すると、全ての文字列が指定されるのと同義となる。

python
Copied!
lis = ['P', 'y', 't', 'h', 'o', 'n']
# 開始位置と終了位置を省略
print(lis[:])
# ['P', 'y', 't', 'h', 'o', 'n']

# 両方とも省略すると先頭から末尾までにアクセスするのと同義となる

増分によるインデックスの「飛ばし」方

[ start : stop : step ] のように3番目のインデックスを指定すると、増分、いわば飛ばし間隔でアクセスできる。

python
Copied!
# リストを定義
lis = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']


# 開始と終了位置は省略、つまり全要素
print(lis[::2])  # 増分 2 を指定
# ['a', 'c', 'e', 'g']
           +---+---+---+---+---+---+---+---+
lis[::2] = |'a'|   |'c'|   |'e'|   |'g'|   |
           +---+---+---+---+---+---+---+---+
           0   1   2   3   4   5   6   7   8  # インデックス
           |   2   |   2   |   2   |          # step 増分
         start                           stop # 開始と終了位置

# 開始位置 1 増分 3 を指定
print(lis[1::3])  # 終了位置は省略、つまり末尾まで
# ['b', 'e', 'h']
            +---+---+---+---+---+---+---+---+
lis[1::3] = |   |'b'|   |   |'e'|   |   |'h'|
            +---+---+---+---+---+---+---+---+
            0   1   2   3   4   5   6   7   8  # インデックス
                |     3     |     3     |      # step 増分
              start                       stop # 開始と終了位置
  • 増分 step の指定では、開始位置の要素も含まれる。
  • 増分を省略した場合の step 1 となる。

マイナスを使ったスライスの使い方

スライス指定に負の値を使用すると後ろからの選択となる。

マイナスを使って後ろから取得

次のサンプルは、スライスのインデックスをマイナスの値にした例。

python
Copied!
# 文字列を定義
url = 'apple.com'

# urlのインデックス
      +---+---+---+---+---+---+---+---+---+
url = | a | p | p | l | e | . | c | o | m |
      +---+---+---+---+---+---+---+---+---+
      0   1   2   3   4   5   6   7   8   9
     -9  -8  -7  -6  -5  -4  -3  -2  -1

終了位置をマイナス指定

[:-4] とすると開始位置が先頭、終了位置が末尾から4つ目までの要素を取得することになる。

python
Copied!
# 文字列を定義
url = 'apple.com'

# 開始位置が先頭、終了位置は末尾から4つ目の要素までを指定
print(url[:-4]) # 0を省略し、先頭を開始位置とする
# apple
           +---+---+---+---+---+---+---+---+---+
url[:-4] = | a | p | p | l | e |   |   |   |   |
           +---+---+---+---+---+---+---+---+---+
           0
                              -4   # マイナスのインデックス
           |                   |
         start                stop # 開始と終了位置

開始位置をマイナス指定

[-4:] とすると開始位置が末尾から4つ目、終了位置が末尾の要素を取得することになる。

ただし、 [-4:-9] のように start > stop で指定してもエラーとはならないが、空の文字列が取得される。

一見、後→前へ逆順に取得するように見えるが step が省略されている場合、値はあくまで正となるため、増分は前→後となる。

python
Copied!
url = 'apple.com'
# 開始位置が末尾から4つ目、終了位置が末尾
print(url[-4:])  # 末尾のインデックスを省略
# .com
           +---+---+---+---+---+---+---+---+---+
url[-4:] = |   |   |   |   |   | . | c | o | m |
           +---+---+---+---+---+---+---+---+---+
                                               9
                              -4
                               |               |
                             start            stop

# 終了位置をマイナスの先頭インデックスで指定
url[-4:-9] 
''   # エラーにはならないが、空の文字列が取得される

マイナスの増分による逆順指定

step にマイナスの値を使うと、配列が反転し、右→左へ逆順に取得していくので、混乱かつわかりにくい部分と言える。さらに、負の増分と終了位置を指定した場合の挙動にクセがあるので要注意。

負の増分を指定するときの理解
  • 配列が逆順となり、末尾 → 先頭のように逆向きに取得していく。
  • 右start から 左stop のように考える。
  • [::-1] のように開始と終了位置を省略した場合は、反転された配列を取得できる。
  • [:4:-1] のように終了位置を指定した場合は、その位置の1つ前まで取得する(要注意)
  • なので、開始(右)から「 start - stopの差 個分」と理解した方がわかりやすい。

負の増分による逆順で先頭まで

[4::-1] とすると開始位置がインデックス 4の位置、終了位置が先頭までの要素を取得することになる。

python
Copied!
# 文字列を定義
url = 'apple.com'
# 開始位置が 4 、終了位置を省略しているので「先頭(左端)」
print(url[4::-1]) # 増分-1なので逆順
# elppa
             +---+---+---+---+---+---+---+---+---+
url[4::-1] = | a | p | p | l | e |   |   |   |   |
             +---+---+---+---+---+---+---+---+---+
             0   1   2   3   4 # 4 → 先頭の順で取得
             |-1 |-1 |-1 |-1 | # -step 負の増分
            stop           start # 開始と終了位置が逆になる

負の増分による反転された配列の取得

[::-1] とすると全要素をまるっと反転された形で取得できる。

python
Copied!
# 文字列を定義
url = 'apple.com'
# 開始と終了位置を省略「末尾(右端)→ 先頭(左端)」の順
print(url[::-1]) # 増分-1なので逆順
# moc.elppa
# 反転された配列が取得できる
             +---+---+---+---+---+---+---+---+---+
url[4::-1] = | a | p | p | l | e | . | c | o | m |
             +---+---+---+---+---+---+---+---+---+
             0   1   2   3   4   5   6   7   8   9 # 末尾 → 先頭の順
             |-1 |-1 |-1 |-1 |-1 |-1 |-1 |-1 |-1 | # -step 負の増分
            stop                               start # 開始と終了位置が逆になる

負の増分、かつ、終了位置の指定による注意すべき挙動

[:4:-1] のように、終了位置を負の増分と一緒に指定した場合、終了位置は、そのインデックスの1つ前までとなる。たとえ [:0:-1] のように終了位置を 0 とした場合でも、1つ前まで( 1 まで)が対象となる。

python
Copied!
# 文字列を定義
url = 'apple.com'
# 開始位置を省略しているので「末尾(右端)」、終了位置が 4 
print(url[:4:-1])
# moc.
# 終了位置のインデックスに 4 を指定しているにもかかわらず、
# 5 の位置までしか取得しないので要注意 
             +---+---+---+---+---+---+---+---+---+
url[:4:-1] = |   |   |   |   |   | . | c | o | m |
             +---+---+---+---+---+---+---+---+---+
                             4   5   6   7   8   9 # 末尾 → 4 の順で取得
                             |-1 |-1 |-1 |-1 |-1 | # -step 負の増分
                            stop               start # 開始と終了位置が逆になる

マイナスの増分を使ったスライスのサンプル

スライス構文に負の増分を使った場合の挙動サンプル。

python
Copied!
# 文字列を定義
url = 'apple.com'
# インデックス早見表
      +---+---+---+---+---+---+---+---+---+
url = | a | p | p | l | e | . | c | o | m |
      +---+---+---+---+---+---+---+---+---+
      0   1   2   3   4   5   6   7   8   9
     -9  -8  -7  -6  -5  -4  -3  -2  -1

# 開始位置が負の値、終了位置に0、増分-1
print(url[-4:0:-1])  
# .elpp  終了位置は1つ前まで
               +---+---+---+---+---+---+---+---+---+
url[-4:0:-1] = |   | p | p | l | e | . |   |   |   |
               +---+---+---+---+---+---+---+---+---+
               0
                                  -4
               |                   |
              stop               start

print(url[-4:0:-2])  
# .lp  終了位置は1つ前まで
               +---+---+---+---+---+---+---+---+---+
url[-4:0:-2] = |   | p |   | l |   | . |   |   |   |
               +---+---+---+---+---+---+---+---+---+
               0
                                  -4
               |   |  -2   |  -2   | # step
              stop               start

print(url[9:-4:-1])  
# moc  終了位置は1つ前まで
               +---+---+---+---+---+---+---+---+---+
url[9:-4:-1] = |   |   |   |   |   |   | c | o | m |
               +---+---+---+---+---+---+---+---+---+
                                                   9
                                  -4
                                   |               |
                                  stop           start

print(url[-1:1:-1])  
# moc.elp  終了位置は1つ前まで
               +---+---+---+---+---+---+---+---+---+
url[-1:1:-1] = |   |   | p | l | e | . | c | o | m |
               +---+---+---+---+---+---+---+---+---+
                   1
                                              -1
                   |                           |
                  stop                       start

スライスによる代入

スライス表記されたイテラブルオブジェクト(文字列・リスト・タプルなど)には、別のイテラブルオブジェクトを代入できる。

スライスによる代入は、要素が結合される。挿入や追加を行いたい場合は【Pythonリスト】要素の追加・結合・挿入 を参照。

置換

例えば下記のリストでは、代入する要素数とスライスによる指定要素数が同じため、そのまま置換され、かつ要素が結合される。

python
Copied!
# リストを定義
lis = ['a', 'b', 'c', 'd', 'e', 'f', 'g']

# lisのインデックス早見表
      +---+---+---+---+---+---+---+
lis = |'a'|'b'|'c'|'d'|'e'|'f'|'g'|
      +---+---+---+---+---+---+---+
      0   1   2   3   4   5   6   7

# 先頭からインデックス 4 の位置までの要素(4つ分)に
# 同じ要素数のリストを代入
lis[:4] = [1, 2, 3, 4]
lis
# [1, 2, 3, 4, 'e', 'f', 'g']
# 指定要素が置換される

リサイズ(拡張)

次の例では、代入するリスト要素の数が異なるため、同じ要素数までは置換され、残りの要素は大きいインデックス側(末尾側)に追加され、リストがリサイズ(拡張)される。

python
Copied!
# リストを定義
lis = ['a', 'b', 'c', 'd', 'e', 'f', 'g']

# lisのインデックス早見表
      +---+---+---+---+---+---+---+
lis = |'a'|'b'|'c'|'d'|'e'|'f'|'g'|
      +---+---+---+---+---+---+---+
      0   1   2   3   4   5   6   7

# 先頭からインデックス 4 の位置までの要素(4つ分)に
# 6つの要素数があるリストを代入
lis[:4] = [1, 2, 3, 4, 5, 6]
lis
# [1, 2, 3, 4, 5, 6, 'e', 'f', 'g']
# 指定インデックスまでは置換され、
# 残りの要素は追加される

step による飛ばし置換

次のサンプルは [::2] のように、増分step を使用してリストを飛び飛びに代入する例。この表記は奇数・偶数のインデックス位置を置き換えたい場合などに使用する。

step によって指定される要素数と、代入しようとする要素数が異なる場合はエラーとなるので注意する。

python
Copied!
# リストを定義
lis = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']

# lisのインデックス早見表
      +---+---+---+---+---+---+---+---+
lis = |'a'|'b'|'c'|'d'|'e'|'f'|'g'|'h'|
      +---+---+---+---+---+---+---+---+
      0   1   2   3   4   5   6   7   8

# stepに 2 を指定したスライス表記
lis[::2]
# ['a', 'c', 'e', 'g'] 先頭から計4つの要素が選択される
           +---+---+---+---+---+---+---+---+
lis[::2] = |'a'|   |'c'|   |'e'|   |'g'|   |
           +---+---+---+---+---+---+---+---+
           0       2       4       6   # 偶数のインデックス

# 参考: 奇数のインデックスの選択
            +---+---+---+---+---+---+---+---+
lis[1::2] = |   |'b'|   |'d'|   |'f'|   |'h'|
            +---+---+---+---+---+---+---+---+
                1       3       5       7   # 奇数のインデックス

# 3つの要素のあるリストを代入してみる
lis[::2] = [1, 2, 3]
# ValueError: attempt to assign sequence of size 3 to extended slice of size 4
# エラーとなるため、4つの要素のあるリストにする必要がある
lis[::2] = [1, 2, 3, 4]
lis
# [1, 'b', 2, 'd', 3, 'f', 4]  偶数のインデックスの位置が置き換わる

# リストを初期化
lis = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
# stepに -2 を指定した負の増分のスライス表記
lis[::-2]
# ['g', 'e', 'c', 'a'] 逆順に計4つの要素が指定される
lis[::-2] = [1, 2, 3, 4]
lis
# [4, 'b', 3, 'd', 2, 'f', 1]  末尾から順に飛び飛びで偶数のインデックスの位置が置き換わる

del文 を使用したリスト要素の削除

スライス表記を使用してリスト要素を削除するには del文 を使用する。

del文 を使用したスライスによる削除は文字列・タプルなどのイミュータブル(不変)なオブジェクトでは使用できないので注意。

先頭から n までのリスト要素を削除

下記の例では、先頭から2つ目までのリスト要素を削除する。

python
Copied!
# リストを定義
lis = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']

# lisのインデックス参考
      +---+---+---+---+---+---+---+---+
lis = |'a'|'b'|'c'|'d'|'e'|'f'|'g'|'h'|
      +---+---+---+---+---+---+---+---+
      0   1   2   3   4   5   6   7   8
# 先頭からインデックス 2 の位置までの要素(2つ分)を削除
del lis[:2]
lis
# ['c', 'd', 'e', 'f', 'g', 'h']

末尾から n までのリスト要素を削除

末尾から2つ目までのリスト要素を削除する。

python
Copied!
# リストを定義
lis = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']

# lisのインデックス参考
      +---+---+---+---+---+---+---+---+
lis = |'a'|'b'|'c'|'d'|'e'|'f'|'g'|'h'|
      +---+---+---+---+---+---+---+---+
      0   1   2   3   4   5   6   7   8
     -8  -7  -6  -5  -4  -3  -2  -1
# 末尾からインデックス -2 の位置までの要素(2つ分)を削除
del lis[-2:]
lis
# ['a', 'b', 'c', 'd', 'e', 'f']

stepによる飛ばし削除

末尾から2つ目までのリスト要素を削除する。

python
Copied!
# リストを定義
lis = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']

# lisのインデックス参考
      +---+---+---+---+---+---+---+---+
lis = |'a'|'b'|'c'|'d'|'e'|'f'|'g'|'h'|
      +---+---+---+---+---+---+---+---+
      0   1   2   3   4   5   6   7   8
     -8  -7  -6  -5  -4  -3  -2  -1
# 末尾からインデックス -2 の位置までの要素(2つ分)を削除
del lis[-2:]
lis
# ['a', 'b', 'c', 'd', 'e', 'f']
目次
上へ