Pythonのリストや文字列にはスライスという機能が備わっているが、
基本的なところしか押さえてなかったので、もう少し踏み込んでみた。
書籍やサイトなども見てみたが、自分が納得できる説明を見かけなかったので、挙動から自分なりに仕様を考えてみた。
ここでは、リストで考えていく。文字列もおそらく同じ挙動だと思う。
lsというリストがあるとする。
スライスは、 ls[A:B:C] で表される。
なお、A,B,Cの引数やセミコロンは指定されなかったり省略されることがある。
(第1セミコロンすらない場合は、そもそもスライスではない。)
まず、大まかな仕様についていうと、
スライスには第1引数(上記のA)、第2引数(上記のB)、第3引数(上記のC)があり、
「始点」となる第1引数と「終点」となる第2引数で要素を拾う範囲を形成し、
第3引数でその範囲の要素を拾う「向き」と「ステップ」を決める。
さらに、もう少し細かいことを付け足すと、
第3引数は、向きとステップを表す。ゼロは指定できない。指定しない場合(デフォルト)は、+1。
第1引数は、自身をリストに反映させる始点。指定しない場合は、第3引数がプラスなら左端、第3引数がマイナスなら右端。
第2引数は、自身をリストに反映させない終点。指定しない場合は、第3引数がプラスなら右端、第3引数がマイナスなら左端。
以上で仕様の説明を終えてもいいのだが、
例を示したほうがいいと思うので、以下に書いていく。
以下に示すlsはリストで、具体的な要素は[ ]の中に書かれている。
各要素の上に書かれている青い数字は正側のインデックス(ゼロも入っているが)で、各要素の下に関われている赤い数字は負側のインデックスを表している。
通常は、正側のインデックスを使うだろう(なお、最後の要素を指定したいときなどは、-1が活躍することもある)。
これを踏まえて、第1、2、3引数の仕様を捉えることで、スライスの仕様を把握できる。
最初に注目すべきは、第3引数である。
上述したが、第3引数は、「向き」と「ステップ」を表す。
正なら第1引数と第2引数で決定づけられる範囲の一番左の要素から右向きに拾っていき、負なら第1引数と第2引数で決定づけられる範囲の一番右の要素から左向きに拾っていく。
ステップとはN個先の要素を拾っていくこと(つまり、N-1個飛ばしで要素を拾っていく)である。
なお、第3引数は表示のうえで省略される(ユーザーが特に指定しない、ということ)ことも多いが、その場合の第3引数は+1である。
次に第1引数を考える。第1引数は、自身をリストの要素として反映させる始点を表す。例えば、上で示したリストの例で、第3引数が正で、かつ、第1引数が2だった場合、以下のイメージとなる。そして、「自身をリストの要素として反映させる」とは、"c"を範囲に含めるということである。
第3引数が負で、かつ、第1引数が2だった場合は以下になる。
第1引数を明確に指定しない場合(デフォルト)も考えておこう。
第3引数が正で、かつ、第1引数を指定しない場合は、以下になる。
第3引数が負で、かつ、第1引数を指定しない場合は、以下になる。
続いて、第2引数について考えよう。
第3引数が正で、かつ、第2引数が4だった場合、以下のようなイメージとなる。
そして、上述した「自身をリストに反映させない」とは、以下の例では"e"を範囲に含めないということである。
第3引数が負で、かつ、第2引数が4だった場合、以下のようなイメージとなる。上記と同様に、以下の例でも"e"を範囲に含めない。
第2引数も明確に指定しないことがある。
第3引数が正で、かつ、第2引数が指定されない場合、以下のように右端を指す。
図に示すように要素を指さない右端なので、「自身を範囲に含めない」という仕様であっても、最後の要素(ここでは、"h")は範囲に含まれる。
第3引数が負で、かつ、第2引数が指定されない場合、以下のように左端を指す。
図に示すように要素を指さない左端なので、「自身を範囲に含めない」という仕様であっても、最後の要素(ここでは、"a")は範囲に含まれる。
このような仕様になっていると考えれば、例えば、
ls[3:5:-1]
としたときに、要素がないことも理解できると思う。
(始点を中心に考えると、)終点は、始点の3よりも左側にあるインデックスを指さないといけない。例えば、2とか。
また、2と同じ位置を指す-6で指しても2と同じ結果が返ってくる。
ls[3:2:-1] と ls[3:-6:-1] は同じということ → ["d"]
上記の仕様を頭に入れた上で、いろいろな事例を見てみると納得いただけると思う。
以上で大体説明できたと思う。
説明不足だと感じたら、追記する。