私はPythonでリストスライシングの基本を理解していると思っていましたが、次のようにスライスでネガティブステップを使用しているときに予期しないエラーを受け取っていました:
>>> a = list(range(10))
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> a[:-1]
[0, 1, 2, 3, 4, 5, 6, 7, 8]
>>> a[::-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
>>> a[:-1:-1]
[]
(これはPython 3.5)で実行されていることに注意してください)
A [:-1:-1]がa [::-1]を使用してリスト全体と同じ方法でa [:-1]スライスを逆方向にステップしないのはなぜですか?
List.reverse()も使用できることを理解していますが、基になるpythonスライス機能をよりよく理解しようとしています。
_-1
_の最初の_a[:-1:-1]
_は、あなたが思うことを意味しません。
スライスでは、負の開始/終了インデックスは文字どおりに解釈されません。代わりに、リストの末尾を簡単に参照するために使用されます(つまり、len(a)
に関連しています)。これは、スライスの方向に関係なく起こります。
この意味は
_a[:-1:-1]
_
と同等です
_a[:len(a)-1:-1]
_
逆スライス中に省略された場合、開始インデックスのデフォルトはlen(a)-1
になり、上記と同等になります
_a[len(a)-1:len(a)-1:-1]
_
開始インデックスと終了インデックスは同じであり、終了インデックスは排他的であるため、これは常に空のリストになります。
0番目の要素まで逆向きにスライスするには、次の表記法のいずれかを使用できます。
_>>> a[::-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
>>> a[:None:-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
>>> a[:-len(a)-1:-1]
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
_
_[1, 2, 3, ...][1:4:1]
_と入力すると、[1, 2, 3, ...][slice(1, 4, 1)]
と同じになります。したがって、_1:4:1
_はslice
オブジェクトの省略形です。 slice
シグネチャはslice(stop)
またはslice(start, stop[, step])
であり、引数にNone
を使用することもできます。
_:: -> slice(None, None, None)
:4 -> slice(4)
# and so on
_
_[a: b: c]
_があるとします。 インデックスのルールは次のようになります。
c
がチェックされます。デフォルトは_+1
_で、c
の符号はステップの順方向または逆方向を示します。 c
の絶対値は、ステップサイズを示します。a
がチェックされている。 c
が正またはNone
の場合、a
のデフォルトは_0
_です。 c
が負の場合、a
のデフォルトは_-1
_です。b
がチェックされます。 c
が正またはNone
の場合、b
のデフォルトはlen
です。 c
が負の場合、b
のデフォルトは-(len+1)
です。注1:Pythonの縮退スライスは適切に処理されます:
len
または_0
_に置き換えられます。c
の場合)が返されます。注2:大まかに言うと、Pythonは、この条件_(a < b) if (c > 0) else (a > b)
_がTrue
(すべてのステップで_a += c
_を更新します。また、すべての負のインデックスは_len - index
_に置き換えられます。
このルールとメモを組み合わせると、空のリストを取得した理由がわかります。あなたの場合:
_ In[1]: [1, 2, 3, 4, 5, 6][:-1:-1] # `c` is negative so `a` is -1 and `b` is -1
Out[1]: []
# it is the same as:
In[2]: [1, 2, 3, 4, 5, 6][-1: -1: -1] # which will produce you an empty list
Out[2]: []
_
スライス表記について非常に良い議論があります: Pythonのスライス表記を説明してください !
私は通常、range
-オブジェクトをスライスすると便利だと思います(これはpython3でのみ可能です-python2ではrange
はlist
を生成し、xrange
はできません特定の長さのリストにどのインデックスが使用されているかを確認する必要がある場合:
>>> range(10)[::-1]
range(9, -1, -1)
>>> range(10)[:-1]
range(0, 9)
そして最後のケースでは:
>>> range(10)[:-1:-1]
range(9, 9, -1)
これは何が起こったのかも説明しています。最初のインデックスは9ですが、9はストップインデックス9より低くありません(pythonでストップインデックスはexcludedであることに注意してください)。素子。
インデックスは連続して適用することもできます:
>>> list(range(10))[::-1][:-1] # first reverse then exclude last item.
[9, 8, 7, 6, 5, 4, 3, 2, 1]
>>> list(range(10))[:-1][::-1] # other way around
[8, 7, 6, 5, 4, 3, 2, 1, 0]
slice
は、range
引数を負の数にすると、step
引数とstart
引数が反対方向に機能するという点で、stop
と同様に機能します。
>>> list(range(9, -1, -1)) == a[::-1]
True
これをより明確にするのに役立ついくつかの例:
>>> a[6:2:-2]
[6, 4]
>>> a[0:None:1] == a[::]
True
>>> a[-1:None:-1] == a[::-1]
True
>>> a[-2:None:-1] == a[:-1][::-1]
True
Pythonのスライスは、最初はかなり単純に見えますが、実際の動作は かなり複雑 です(注3と5が関連しています)。スライス_a[i:j:k]
_がある場合:
i
またはj
が負の場合、a
の最後からインデックスを参照します(したがって、_a[-1]
_はa
の最後の要素を参照します)i
またはj
が指定されていない場合、またはNone
である場合、デフォルトはa
の終わりですが、which終了はk
の符号に依存します:
k
が正の場合、前方にスライスしているため、i
は0になり、j
はlen(a)
になりますk
が負の場合、後方にスライスしているので、i
はlen(a)
になり、j
はa
の開始前の要素になります。
NB:j
cannotは-1に置き換えられます。Pythonは、j
を_a[0]
_の前の(存在しない)要素ではなく、a
のlast要素として処理します。目的の動作を取得するには、j
の代わりに-len(a)-1
(または-(len(a)+1)
)を使用する必要があります。つまり、_a[j]
_に到達するには、スライスはa
の最後の要素は、len(a)
要素のために左に移動し、さらにもう1つの要素を残して、a
が開始する前に終了し、スライスに_a[0]
_を含めます。
したがって、_a[:-1:-1]
_は、「a
の最後から_a[-1]
_(i
が指定されておらず、k
が負であるため)の最後から最後の要素に移動することを意味しますof a
(_j == -1
_以降)、ステップサイズ-1 "。 i
とj
は等しい-同じ場所でスライスを開始および停止するため、式は空のリストに評価されます。
_a[:-1]
_を逆にするには、_a[-2::-1]
_を使用できます。この方法では、スライスは最後から2番目の要素_a[-2]
_から始まり(_a[:-1]
_には_a[-1]
_が含まれないため)、_a[0]
_の「前」の要素まで後方に移動します。つまり、_a[0]
_はスライスに含まれています。
_>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> a[:-1]
[0, 1, 2, 3, 4, 5, 6, 7, 8]
>>> a[-2::-1]
[8, 7, 6, 5, 4, 3, 2, 1, 0]
_