web-dev-qa-db-ja.com

スライス表記について

私はPythonのスライス記法に関する良い説明(参照はプラスです)を必要とします。

私にとっては、この表記法には少し注意が必要です。

それは非常に強力に見えます、しかし私はそれのまわりで私の頭をあまり持っていませんでした。

2730
Simon

それは本当に簡単です:

a[start:stop]  # items start through stop-1
a[start:]      # items start through the rest of the array
a[:stop]       # items from the beginning through stop-1
a[:]           # a copy of the whole array

stepの値もあります。これは上記のいずれにも使用できます。

a[start:stop:step] # start through not past stop, by step

覚えておくべき重要な点は、:stop値は、選択されたスライスの最初の値である{notです。そのため、stopstartの違いは、選択されている要素の数です(stepが1の場合、デフォルト)。

もう1つの機能は、startまたはstopの数である可能性があることです。これは、配列の先頭ではなく末尾から数えることを意味します。そう:

a[-1]    # last item in the array
a[-2:]   # last two items in the array
a[:-2]   # everything except the last two items

同様に、stepは負の数になります。

a[::-1]    # all items in the array, reversed
a[1::-1]   # the first two items, reversed
a[:-3:-1]  # the last two items, reversed
a[-3::-1]  # everything except the last two items, reversed

あなたが望むより少ない項目があれば、Pythonはプログラマーに優しいです。たとえば、a[:-2]を要求し、aに1つの要素しか含まれていない場合は、エラーではなく空のリストが表示されます。時々あなたはエラーを好むでしょう、それでこれが起こるかもしれないことに注意しなければなりません。

slice()オブジェクトとの関係

スライス演算子[]は実際には上記のコードで:表記法を使ってslice()オブジェクトと共に使われています。これは[]内でのみ有効です。

a[start:stop:step]

以下と同等です。

a[slice(start, stop, step)]

スライスオブジェクトも、range()と同様に、引数の数に応じてわずかに異なる動作をします。つまり、slice(stop)slice(start, stop[, step])の両方がサポートされています。与えられた引数の指定をスキップするには、Noneを使うかもしれません。 a[start:]a[slice(start, None)]と同等、またはa[::-1]a[slice(None, None, -1)]と同等です。

:ベースの表記は単純なスライスには非常に役立ちますが、slice()オブジェクトを明示的に使用することでプログラムによるスライスの生成が簡単になります。

3725
Greg Hewgill

Pythonチュートリアル はそれについて話しています(スライスについての部分に達するまで少しスクロールダウンしてください)。

ASCIIアート図は、スライスがどのように機能するかを覚えておくのにも役立ちます。

 +---+---+---+---+---+---+
 | P | y | t | h | o | n |
 +---+---+---+---+---+---+
 0   1   2   3   4   5   6
-6  -5  -4  -3  -2  -1

スライスがどのように機能するかを覚えておくための1つの方法は、インデックスを 文字とみなし、最初の文字の左端に0の番号を付けることです。次に n の文字列の最後の文字の右端文字はindex n を持ちます。

480
Hans Nowak

文法によって許される可能性を列挙する:

>>> seq[:]                # [seq[0],   seq[1],          ..., seq[-1]    ]
>>> seq[low:]             # [seq[low], seq[low+1],      ..., seq[-1]    ]
>>> seq[:high]            # [seq[0],   seq[1],          ..., seq[high-1]]
>>> seq[low:high]         # [seq[low], seq[low+1],      ..., seq[high-1]]
>>> seq[::stride]         # [seq[0],   seq[stride],     ..., seq[-1]    ]
>>> seq[low::stride]      # [seq[low], seq[low+stride], ..., seq[-1]    ]
>>> seq[:high:stride]     # [seq[0],   seq[stride],     ..., seq[high-1]]
>>> seq[low:high:stride]  # [seq[low], seq[low+stride], ..., seq[high-1]]

もちろん、(high-low)%stride != 0の場合、終点はhigh-1より少し低くなります。

strideが負の値の場合、カウントダウンしているので順序が少し変わります。

>>> seq[::-stride]        # [seq[-1],   seq[-1-stride],   ..., seq[0]    ]
>>> seq[high::-stride]    # [seq[high], seq[high-stride], ..., seq[0]    ]
>>> seq[:low:-stride]     # [seq[-1],   seq[-1-stride],   ..., seq[low+1]]
>>> seq[high:low:-stride] # [seq[high], seq[high-stride], ..., seq[low+1]]

拡張スライシング(コンマと省略記号付き)は、主に(NumPyのような)特別なデータ構造によってのみ使用されます。基本シーケンスはそれらをサポートしていません。

>>> class slicee:
...     def __getitem__(self, item):
...         return repr(item)
...
>>> slicee()[0, 1:2, ::5, ...]
'(0, slice(1, 2, None), slice(None, None, 5), Ellipsis)'
363
ephemient

上記の答えはスライスの割り当てについては説明していません。スライスの割り当てを理解するために、ASCIIアートに別の概念を追加すると便利です。

                +---+---+---+---+---+---+
                | P | y | t | h | o | n |
                +---+---+---+---+---+---+
Slice position: 0   1   2   3   4   5   6
Index position:   0   1   2   3   4   5

>>> p = ['P','y','t','h','o','n']
# Why the two sets of numbers:
# indexing gives items, not lists
>>> p[0]
 'P'
>>> p[5]
 'n'

# Slicing gives lists
>>> p[0:1]
 ['P']
>>> p[0:2]
 ['P','y']

1つの発見的方法は、0からnまでのスライスに対して、「0が始まりで始まり、リストの中のn個の項目を取る」と考えます。

>>> p[5] # the last of six items, indexed from zero
 'n'
>>> p[0:5] # does NOT include the last item!
 ['P','y','t','h','o']
>>> p[0:6] # not p[0:5]!!!
 ['P','y','t','h','o','n']

別の発見的方法は、「どのスライスについても、開始位置をゼロに置き換え、前の発見的方法を適用してリストの終わりを取得し、最初の数を数えて最初から数えて項目を切り捨てる」というものです。

>>> p[0:4] # Start at the beginning and count out 4 items
 ['P','y','t','h']
>>> p[1:4] # Take one item off the front
 ['y','t','h']
>>> p[2:4] # Take two items off the front
 ['t','h']
# etc.

スライス代入の最初の規則は、slicing リストを返すので、スライス代入リスト(または他の反復可能)を必要とすることです。

>>> p[2:3]
 ['t']
>>> p[2:3] = ['T']
>>> p
 ['P','y','T','h','o','n']
>>> p[2:3] = 't'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only assign an iterable

スライス割り当ての2番目の規則は、上にも示したように、リストのどの部分もスライスインデックス付けによって返されるということです。これはスライス割り当てによって変更される部分と同じです。

>>> p[2:4]
 ['T','h']
>>> p[2:4] = ['t','r']
>>> p
 ['P','y','t','r','o','n']

スライス割り当ての3番目の規則は、割り当てられたリスト(反復可能)の長さが同じである必要はないということです。インデックス付きのスライスは単純にスライスされ、割り当てられているものにまとめて置き換えられます。

>>> p = ['P','y','t','h','o','n'] # Start over
>>> p[2:4] = ['s','p','a','m']
>>> p
 ['P','y','s','p','a','m','o','n']

慣れるのが一番難しい部分は、空のスライスへの代入です。ヒューリスティックな1と2を使うと、indexingを空のスライスに向けるのは簡単です。

>>> p = ['P','y','t','h','o','n']
>>> p[0:4]
 ['P','y','t','h']
>>> p[1:4]
 ['y','t','h']
>>> p[2:4]
 ['t','h']
>>> p[3:4]
 ['h']
>>> p[4:4]
 []

そして、一度それを見たら、空のスライスへのスライスの割り当ても意味があります。

>>> p = ['P','y','t','h','o','n']
>>> p[2:4] = ['x','y'] # Assigned list is same length as slice
>>> p
 ['P','y','x','y','o','n'] # Result is same length
>>> p = ['P','y','t','h','o','n']
>>> p[3:4] = ['x','y'] # Assigned list is longer than slice
>>> p
 ['P','y','t','x','y','o','n'] # The result is longer
>>> p = ['P','y','t','h','o','n']
>>> p[4:4] = ['x','y']
>>> p
 ['P','y','t','h','x','y','o','n'] # The result is longer still

スライスの2番目の番号(4)は変更していないので、空のスライスに割り当てている場合でも、挿入された項目は常に 'o'のすぐ上に重なります。したがって、空のスライス割り当ての位置は、空でないスライス割り当ての位置の論理的な拡張です。

少しバックアップをとって、スライスのカウントアップを始めようとしているとどうなりますか。

>>> p = ['P','y','t','h','o','n']
>>> p[0:4]
 ['P','y','t','h']
>>> p[1:4]
 ['y','t','h']
>>> p[2:4]
 ['t','h']
>>> p[3:4]
 ['h']
>>> p[4:4]
 []
>>> p[5:4]
 []
>>> p[6:4]
 []

スライスを使用すると、作業が完了すれば完了です。それは後方にスライスし始めません。 Pythonでは、負の数を使用して明示的に要求しない限り、負のストライドは発生しません。

>>> p[5:3:-1]
 ['n','o']

「いったん終わったら、終わった」というルールには、いくつかの奇妙な結果があります。

>>> p[4:4]
 []
>>> p[5:4]
 []
>>> p[6:4]
 []
>>> p[6]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: list index out of range

実際、索引付けと比較して、Pythonのスライシングは奇妙にエラープルーフです。

>>> p[100:200]
 []
>>> p[int(2e99):int(1e99)]
 []

これは時々便利になるかもしれませんが、それはまた幾分奇妙な振る舞いにつながることができます:

>>> p
 ['P', 'y', 't', 'h', 'o', 'n']
>>> p[int(2e99):int(1e99)] = ['p','o','w','e','r']
>>> p
 ['P', 'y', 't', 'h', 'o', 'n', 'p', 'o', 'w', 'e', 'r']

あなたのアプリケーションに依存しますが、そうではないかもしれませんし、そうではないかもしれません...あなたがそこに望んでいたものであるかもしれません!


以下は私の最初の答えのテキストです。これは多くの人にとって便利なので、削除したくはありませんでした。

>>> r=[1,2,3,4]
>>> r[1:1]
[]
>>> r[1:1]=[9,8]
>>> r
[1, 9, 8, 2, 3, 4]
>>> r[1:1]=['blah']
>>> r
[1, 'blah', 9, 8, 2, 3, 4]

これにより、スライスとインデックスの違いも明らかになります。

266

Pythonのスライス表記を説明する

要するに、サブスクリプト表記(:)のコロン(subscriptable[subscriptarg])はスライス表記を作成します-これにはオプションの引数startstopstepがあります。

sliceable[start:stop:step]

Pythonスライシングは、データの一部に系統的にアクセスするための計算上高速な方法です。私の意見では、中級のPythonプログラマーであるためには、言語の1つの側面である必要があります。

重要な定義

はじめに、いくつかの用語を定義しましょう。

start:スライスの開始インデックス。stopと同じでない限り、このインデックスの要素が含まれます。デフォルトは0、つまり最初のインデックスです。負の場合、nアイテムを最後から開始することを意味します。

stop:スライスの終了インデックス、それはnotこのインデックスの要素を含み、デフォルトはシーケンスの長さスライスされます。つまり、最後までです。

step:インデックスが増加する量。デフォルトは1です。負の場合、イテレート可能オブジェクトを逆にスライスします。

インデックス作成の仕組み

これらの正または負の数値を作成できます。正の数の意味は簡単ですが、負の数の場合、Pythonのインデックスと同様に、startおよびstopの終わりから逆向きにカウントし、- step、単にインデックスをデクリメントします。この例は ドキュメントのチュートリアルより ですが、各インデックスが参照するシーケンス内のアイテムを示すために少し変更しました:

 +---+---+---+---+---+---+
 | P | y | t | h | o | n |
 +---+---+---+---+---+---+
   0   1   2   3   4   5 
  -6  -5  -4  -3  -2  -1

スライスの仕組み

それをサポートするシーケンスでスライス表記を使用するには、シーケンスに続く角括弧に少なくとも1つのコロンを含める必要があります(実際には シーケンスの__getitem__メソッドを実装し、Pythonデータモデル 。)

スライス表記は次のように機能します。

sequence[start:stop:step]

また、startstop、およびstepにはデフォルトがあるため、デフォルトにアクセスするには引数を省略してください。

リストから最後の9つの要素(または文字列のようにそれをサポートする他のシーケンス)を取得するスライス表記は次のようになります。

my_list[-9:]

これを見たとき、括弧内の部分を「最後から9番目」と読みました。 (実際には、精神的に「-9、オン」と略しています)

説明:

完全な表記は

my_list[-9:None:None]

そして、デフォルトを置き換えるために(実際にstepが負の場合、stopのデフォルトは-len(my_list) - 1なので、停止のためのNoneは、実際には、どちらの終了ステップに進むかを意味します) :

my_list[-9:len(my_list):1]

colon:は、Pythonに、通常のインデックスではなくスライスを与えていることを伝えます。 Python 2のリストの浅いコピーを作成する慣用的な方法は、

list_copy = sequence[:]

そしてそれらをクリアするのは:

del my_list[:]

(Python 3はlist.copyおよびlist.clearメソッドを取得します。)

stepが負の場合、startおよびstopのデフォルトは変更されます

デフォルトでは、step引数が空(またはNone)の場合、+1に割り当てられます。

しかし、負の整数を渡すことができ、リスト(または他のほとんどの標準スライス可能オブジェクト)は最後から最初にスライスされます。

したがって、負のスライスはstartおよびstopのデフォルトを変更します!

ソースでこれを確認する

私はユーザーにソースだけでなくドキュメントも読むように勧めています。 スライスオブジェクトとこのロジックのソースコードはここにあります 。まず、stepが負かどうかを判断します。

 step_is_negative = step_sign < 0;

その場合、下限は-1であり、先頭まですべてスライスします。上限は長さから1を引いた値であり、末尾から開始することを意味します。 (この-1のセマンティクスはdifferentから-1であることに注意してください。ユーザーはPythonで最後のアイテムを示すインデックスを渡すことができます。)

if (step_is_negative) {
    lower = PyLong_FromLong(-1L);
    if (lower == NULL)
        goto error;

    upper = PyNumber_Add(length, lower);
    if (upper == NULL)
        goto error;
}

それ以外の場合、stepは正であり、下限はゼロであり、上限(スライスリストの長さは上限ではありません)になります。

else {
    lower = _PyLong_Zero;
    Py_INCREF(lower);
    upper = length;
    Py_INCREF(upper);
}

次に、startstopのデフォルトを適用する必要があります。startのデフォルトは、stepが負の場合の上限として計算されます。

if (self->start == Py_None) {
    start = step_is_negative ? upper : lower;
    Py_INCREF(start);
}

およびstop、下限:

if (self->stop == Py_None) {
    stop = step_is_negative ? lower : upper;
    Py_INCREF(stop);
}

スライスにわかりやすい名前を付けてください!

スライスの形成をlist.__getitem__メソッドに渡すことから分離すると便利な場合があります( 角括弧の役割 )。慣れていない場合でも、コードを読みやすくすることで、コードを読まなければならない人があなたが何をしているかをより簡単に理解できるようになります。

ただし、コロンで区切られた整数を変数に単に割り当てることはできません。スライスオブジェクトを使用する必要があります。

last_nine_slice = slice(-9, None)

2番目の引数Noneは必須です。そのため、最初の引数はstart引数として解釈されます それ以外の場合はstop引数になります

その後、スライスオブジェクトをシーケンスに渡すことができます。

>>> list(range(100))[last_nine_slice]
[91, 92, 93, 94, 95, 96, 97, 98, 99]

範囲もスライスをとるのは興味深いです:

>>> range(100)[last_nine_slice]
range(91, 100)

メモリに関する考慮事項:

Pythonリストのスライスはメモリ内に新しいオブジェクトを作成するため、注意すべきもう1つの重要な機能はitertools.isliceです。通常、スライスをメモリ内で静的に作成するだけでなく、スライスを反復処理する必要があります。 isliceはこれに最適です。注意点として、startstop、またはstepへの負の引数はサポートされていないため、それが問題になる場合は、事前にインデックスを計算するか、反復可能要素を逆にする必要があります。

length = 100
last_nine_iter = itertools.islice(list(range(length)), length-9, None, 1)
list_last_nine = list(last_nine_iter)

そしていま:

>>> list_last_nine
[91, 92, 93, 94, 95, 96, 97, 98, 99]

リストスライスがコピーを作成するという事実は、リスト自体の機能です。 Pandas DataFrameのような高度なオブジェクトをスライスしている場合、コピーではなく、元のビューを返す場合があります。

234
Aaron Hall

スライス構文を初めて見たときには、すぐには明らかにならなかった2つのことがあります。

>>> x = [1,2,3,4,5,6]
>>> x[::-1]
[6,5,4,3,2,1]

順序を逆にする簡単な方法!

そして、あなたが望むなら、何らかの理由で、逆の順序で2番目の項目ごとに:

>>> x = [1,2,3,4,5,6]
>>> x[::-2]
[6,4,2]
138
Dana

Python 2.7では

Pythonでのスライス

[a:b:c]

len = length of string, Tuple or list

c -- default is +1. The sign of c indicates forward or backward, absolute value of c indicates steps. Default is forward with step size 1. Positive means forward, negative means backward.

a --  When c is positive or blank, default is 0. When c is negative, default is -1.

b --  When c is positive or blank, default is len. When c is negative, default is -(len+1).

インデックス割り当てを理解することは非常に重要です。

In forward direction, starts at 0 and ends at len-1

In backward direction, starts at -1 and ends at -len

[a:b:c]と言うときは、cの符号に応じて(前方または後方)、aから始まりbで終わる(b番目のインデックスの要素を除く)ということです。上記の索引付け規則を使用し、この範囲の要素のみが見つかることを忘れないでください。

-len, -len+1, -len+2, ..., 0, 1, 2,3,4 , len -1

しかし、この範囲は両方向に無限に続きます。

...,-len -2 ,-len-1,-len, -len+1, -len+2, ..., 0, 1, 2,3,4 , len -1, len, len +1, len+2 , ....

例えば:

             0    1    2   3    4   5   6   7   8   9   10   11
             a    s    t   r    i   n   g
    -9  -8  -7   -6   -5  -4   -3  -2  -1

上のa、b、cのルールを使用してトラバースするときにa、b、およびcを選択して上の範囲とオーバーラップできる場合は、エレメントを含むリスト(トラバース中にタッチ)を取得するか、空のリストを取得します。

最後の1つ:aとbが等しい場合は、空のリストも表示されます。

>>> l1
[2, 3, 4]

>>> l1[:]
[2, 3, 4]

>>> l1[::-1] # a default is -1 , b default is -(len+1)
[4, 3, 2]

>>> l1[:-4:-1] # a default is -1
[4, 3, 2]

>>> l1[:-3:-1] # a default is -1
[4, 3]

>>> l1[::] # c default is +1, so a default is 0, b default is len
[2, 3, 4]

>>> l1[::-1] # c is -1 , so a default is -1 and b default is -(len+1)
[4, 3, 2]


>>> l1[-100:-200:-1] # Interesting
[]

>>> l1[-1:-200:-1] # Interesting
[4, 3, 2]


>>> l1[-1:-1:1]
[]


>>> l1[-1:5:1] # Interesting
[4]


>>> l1[1:-7:1]
[]

>>> l1[1:-7:-1] # Interesting
[3, 2]

>>> l1[:-2:-2] # a default is -1, stop(b) at -2 , step(c) by 2 in reverse direction
[4]
93
abc

この素晴らしいテーブルは http://wiki.python.org/moin/MovingToPythonFromOtherLanguagesにあります

Python indexes and slices for a six-element list.
Indexes enumerate the elements, slices enumerate the spaces between the elements.

Index from rear:    -6  -5  -4  -3  -2  -1      a=[0,1,2,3,4,5]    a[1:]==[1,2,3,4,5]
Index from front:    0   1   2   3   4   5      len(a)==6          a[:5]==[0,1,2,3,4]
                   +---+---+---+---+---+---+    a[0]==0            a[:-2]==[0,1,2,3]
                   | a | b | c | d | e | f |    a[5]==5            a[1:2]==[1]
                   +---+---+---+---+---+---+    a[-1]==5           a[1:-1]==[1,2,3,4]
Slice from front:  :   1   2   3   4   5   :    a[-2]==4
Slice from rear:   :  -5  -4  -3  -2  -1   :
                                                b=a[:]
                                                b==[0,1,2,3,4,5] (shallow copy of a)
91
AdrianoFerrari

それを少し使用した後、私は最も簡単な説明がそれがforループの引数と全く同じであるということであることを理解しています...

(from:to:step)

いずれもオプションです。

(:to:step)
(from::step)
(from:to)

それからそれを理解するために、負のインデックスは負のインデックスに文字列の長さを追加することだけを必要とします。

とにかくこれは私のために働きます...

58
Simon

私はそれがどのように機能するかを覚えておくのがより簡単であると思います、そして私はどんな特定の開始/停止/ステップの組み合わせでも理解することができます。

最初にrange()を理解することは有益です。

def range(start=0, stop, step=1):  # Illegal syntax, but that's the effect
    i = start
    while (i < stop if step > 0 else i > stop):
        yield i
        i += step

startから始めて、stepだけインクリメントし、stopに到達しないでください。とても簡単です。

否定的なステップについて覚えておくべきことは、それが高いか低いかにかかわらず、stopは常に除外された終わりであるということです。同じスライスを逆の順序で使用する場合は、反転を個別に実行するほうがはるかにクリーンです。 'abcde'[1:-2][::-1]は、左から1文字、右から2文字切り、その後反転します。 ( reversed() もご覧ください。)

シーケンススライスは、負のインデックスを最初に正規化する点を除いて同じです。シーケンススライスは、シーケンス外に出ることはありません。

_ todo _ :以下のコードはabs(step)> 1のときに「決してシーケンスの外に出ない」というバグがありました。 I thinkそれが正しいようにパッチを当てましたが、理解するのは難しいです。

def this_is_how_slicing_works(seq, start=None, stop=None, step=1):
    if start is None:
        start = (0 if step > 0 else len(seq)-1)
    Elif start < 0:
        start += len(seq)
    if not 0 <= start < len(seq):  # clip if still outside bounds
        start = (0 if step > 0 else len(seq)-1)
    if stop is None:
        stop = (len(seq) if step > 0 else -1)  # really -1, not last element
    Elif stop < 0:
        stop += len(seq)
    for i in range(start, stop, step):
        if 0 <= i < len(seq):
            yield seq[i]

is Noneの詳細を気にする必要はありません - startstopを省略すると、シーケンス全体が正しく表示されるようになります。

負のインデックスを正規化すると、最初は開始から終了までを独立してカウントできます。range(1,-2) == []にもかかわらず'abcde'[1:-2] == 'abcde'[1:3] == 'bc'。正規化は「長さのモジュロ」と考えられることがありますが、長さが1回だけ加算されることに注意してください。 'abcde'[-53:42]は単なる文字列全体です。

Index:
      ------------>
  0   1   2   3   4
+---+---+---+---+---+
| a | b | c | d | e |
+---+---+---+---+---+
  0  -4  -3  -2  -1
      <------------

Slice:
    <---------------|
|--------------->
:   1   2   3   4   :
+---+---+---+---+---+
| a | b | c | d | e |
+---+---+---+---+---+
:  -4  -3  -2  -1   :
|--------------->
    <---------------|

これがPythonでリストをモデル化するのに役立つことを願っています。

参照: http://wiki.python.org/moin/MovingToPythonFromOtherLanguages

36
xiaoyu

私は自分自身について考えるのに "要素間のインデックスポイント"という方法を使いますが、それを説明する一つの方法は他の人がそれを手に入れるのを助けることがあります:

mylist[X:Y]

Xはあなたが欲しい最初の要素のインデックスです。
Yはあなたが しない 欲しい最初の要素のインデックスです。

35
Steve Losh

Pythonスライス表記

a[start:end:step]
  • startendの場合、負の値はシーケンスの終わりを基準にしていると解釈されます。
  • endの正の添字は位置afterを含む最後の要素を示します。
  • 空白の値はデフォルトで次のようになっています:[+0:-0:1]
  • 負のステップを使用すると、startendの解釈が逆になります

この表記法は、(派手な)行列や多次元配列にも適用されます。たとえば、列全体をスライスするには、次のようにします。

m[::,0:2:] ## slice the first two columns

スライスは配列要素のコピーではなく参照を保持します。別のコピーを作成したい場合は、 deepcopy() を使用できます。

34
nobar

これが私がスライスを初心者に教える方法です:

インデックスとスライスの違いを理解する:

Wiki Pythonには、この驚くべき絵があります。これは、インデックス作成とスライス作成を明確に区別しています。

enter image description here

それは6つの要素を含むリストです。スライスをよりよく理解するために、そのリストを6つのボックスのセットとしてまとめて考えてみましょう。各ボックスにはアルファベットがあります。

索引付けは、boxの内容を扱うようなものです。あなたはどんな箱の中身もチェックすることができます。しかし、一度に複数のボックスの内容を確認することはできません。箱の中身も入れ替えることができます。しかし、あなたは1箱に2個のボールを入れることも、一度に2個のボールを置き換えることもできません。

In [122]: alpha = ['a', 'b', 'c', 'd', 'e', 'f']

In [123]: alpha
Out[123]: ['a', 'b', 'c', 'd', 'e', 'f']

In [124]: alpha[0]
Out[124]: 'a'

In [127]: alpha[0] = 'A'

In [128]: alpha
Out[128]: ['A', 'b', 'c', 'd', 'e', 'f']

In [129]: alpha[0,1]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-129-c7eb16585371> in <module>()
----> 1 alpha[0,1]

TypeError: list indices must be integers, not Tuple

スライスは箱そのものを扱うようなものです。あなたは最初の箱をピックアップして別のテーブルの上に置くことができます。箱を拾うためにあなたが知る必要があるのは箱の始めと終わりの位置です。

最初と最後の2箱、あるいは1と4の間のすべての箱をピックアップすることもできます。この位置は開始位置と停止位置と呼ばれます。

面白いのは、あなたが一度に複数の箱を交換することができるということです。また、あなたは好きな場所に複数のボックスを配置することができます。

In [130]: alpha[0:1]
Out[130]: ['A']

In [131]: alpha[0:1] = 'a'

In [132]: alpha
Out[132]: ['a', 'b', 'c', 'd', 'e', 'f']

In [133]: alpha[0:2] = ['A', 'B']

In [134]: alpha
Out[134]: ['A', 'B', 'c', 'd', 'e', 'f']

In [135]: alpha[2:2] = ['x', 'xx']

In [136]: alpha
Out[136]: ['A', 'B', 'x', 'xx', 'c', 'd', 'e', 'f']

ステップ付きスライス:

今まであなたは連続的に箱を選んできました。しかし時々あなたは別々にピックアップする必要があります。例えば、あなたは2箱おきに拾うことができます。最後から3箱おきにピックアップすることもできます。この値はステップサイズと呼ばれます。これはあなたの連続ピックアップ間のギャップを表します。あなたが最初から最後まで、そしてその逆に箱を選ぶのであれば、ステップサイズは正になるはずです。

In [137]: alpha = ['a', 'b', 'c', 'd', 'e', 'f']

In [142]: alpha[1:5:2] 
Out[142]: ['b', 'd']

In [143]: alpha[-1:-5:-2]
Out[143]: ['f', 'd']

In [144]: alpha[1:5:-2]
Out[144]: []

In [145]: alpha[-1:-5:2]      
Out[145]: []

Pythonが欠けているパラメータをどのように計算するか:

パラメータを省略してスライスした場合、Pythonは自動的にそれを見つけようとします。

CPythonのソースコードをチェックすると、PySlice_GetIndicesExという名前の関数が見つかります。これは与えられたパラメータのスライスへのインデックスを計算します。これがPythonの論理的に等価なコードです。

この関数はスライスのためにPythonオブジェクトとオプションのパラメータを取り、要求されたスライスの開始、停止、ステップとスライスの長さを返します。

def py_slice_get_indices_ex(obj, start=None, stop=None, step=None):

    length = len(obj)

    if step is None:
        step = 1
    if step == 0:
        raise Exception("Step cannot be zero.")

    if start is None:
        start = 0 if step > 0 else length - 1
    else:
        if start < 0:
            start += length
        if start < 0:
            start = 0 if step > 0 else -1
        if start >= length:
            start = length if step > 0 else length - 1

    if stop is None:
        stop = length if step > 0 else -1
    else:
        if stop < 0:
            stop += length
        if stop < 0:
            stop = 0 if step > 0 else -1
        if stop >= length:
            stop = length if step > 0 else length - 1

    if (step < 0 and stop >= start) or (step > 0 and start >= stop):
        slice_length = 0
    Elif step < 0:
        slice_length = (stop - start + 1)/(step) + 1
    else:
        slice_length = (stop - start - 1)/(step) + 1

    return (start, stop, step, slice_length)

これがスライスの背後に存在するインテリジェンスです。 Pythonにはsliceという関数が組み込まれているので、いくつかのパラメータを渡して、不足しているパラメータをどの程度スマートに計算できるかを確認できます。

In [21]: alpha = ['a', 'b', 'c', 'd', 'e', 'f']

In [22]: s = slice(None, None, None)

In [23]: s
Out[23]: slice(None, None, None)

In [24]: s.indices(len(alpha)) 
Out[24]: (0, 6, 1)

In [25]: range(*s.indices(len(alpha)))
Out[25]: [0, 1, 2, 3, 4, 5]

In [26]: s = slice(None, None, -1) 

In [27]: range(*s.indices(len(alpha)))
Out[27]: [5, 4, 3, 2, 1, 0]

In [28]: s = slice(None, 3, -1)        

In [29]: range(*s.indices(len(alpha)))
Out[29]: [5, 4]

注: この投稿は、もともと私のブログに書かれています http://www.avilpage.com/2015/03/a-slice-of-python-intelligence-behind.html

31
ChillarAnand

これはいくつかの追加情報のためだけです...下記のリストを考えてください

>>> l=[12,23,345,456,67,7,945,467]

リストを逆にするための他のトリックはほとんどありません。

>>> l[len(l):-len(l)-1:-1]
[467, 945, 7, 67, 456, 345, 23, 12]

>>> l[:-len(l)-1:-1]
[467, 945, 7, 67, 456, 345, 23, 12]

>>> l[len(l)::-1]
[467, 945, 7, 67, 456, 345, 23, 12]

>>> l[::-1]
[467, 945, 7, 67, 456, 345, 23, 12]

>>> l[-1:-len(l)-1:-1]
[467, 945, 7, 67, 456, 345, 23, 12]
30

スライス割り当てを使用して、リストから1つ以上の要素を削除することもできます。

r = [1, 'blah', 9, 8, 2, 3, 4]
>>> r[1:4] = []
>>> r
[1, 2, 3, 4]
29
dansalmo

一般的な規則として、たくさんのハードコードされたインデックス値でコードを書くことは読みやすさとメンテナンスの混乱につながります。たとえば、1年後にコードに戻った場合、それを見て、それを書いたときに何を考えていたのか疑問に思うでしょう。示されている解決策は、単にコードが実際に何をしているのかをより明確に述べる方法です。一般に、組み込みのslice()はスライスが許されるところならどこでも使用できるスライスオブジェクトを作成します。例えば:

>>> items = [0, 1, 2, 3, 4, 5, 6]
>>> a = slice(2, 4)
>>> items[2:4]
[2, 3]
>>> items[a]
[2, 3]
>>> items[a] = [10,11]
>>> items
[0, 1, 10, 11, 4, 5, 6]
>>> del items[a]
>>> items
[0, 1, 4, 5, 6]

スライスインスタンスsがある場合は、それぞれそのs.start、s.stop、およびs.step属性を調べることで、それに関する詳細情報を取得できます。例えば:

>>> a = slice(10, 50, 2)
>>> a.start
10
>>> a.stop
50
>>> a.step
2
>>>
26
Python_Dude

1.スライス表記

わかりやすくするために、 スライスの形式は1つだけです。 /

s[start:end:step]

そしてこれがどのように機能するかです:

  • s:スライスできるオブジェクト
  • start:繰り返しを開始する最初のインデックス
  • end:最後のインデックス、endインデックスは結果のスライスに含まれないことに注意してください
  • stepstepインデックスごとに要素を選ぶ

もう一つ重要なこと: すべてのstartendstepは省略可能です。 そしてそれらが省略された場合、それらのデフォルト値が使用されます:0len(s)1

そのため、可能なバリエーションは以下のとおりです。

# mostly used variations
s[start:end]
s[start:]
s[:end]

# step related variations
s[:end:step]
s[start::step]
s[::step]

# make a copy
s[:]

注:start>=endstep>0の場合のみ考慮)の場合、pythonは空のスライス[]を返します。

落とし穴

上の部分はスライスがどのように機能するかについての中心的な機能を説明します、それはほとんどの場合に機能します。ただし、気を付けなければならない落とし穴がある可能性があります、そしてこの部分はそれらを説明します。

負のインデックス

Pythonの学習者を最初に混乱させるのは、 indexが負になる可能性があるということです。 パニックにならないでください: 負のインデックスは後方からのカウントを意味します。

例えば:

s[-5:]    # start at the 5th index from the end of array, 
          # thus returns the last 5 elements
s[:-5]    # start at index 0, end until the 5th index from end of array, 
          # thus returns s[0:len(s)-5]

否定的なステップ

もっと混乱させるのは、stepもマイナスになる可能性があるということです!

負のステップは、終了インデックスを含め、終了インデックスを含め、開始インデックスを結果から除外して、配列を逆方向に繰り返すことを意味します。

_ note _ :stepが負の場合、startからlen(s)のデフォルト値(0にはs[::-1]が含まれるため、ends[0]と等しくありません)。例えば:

s[::-1]            # reversed slice
s[len(s)::-1]      # same as above, reversed slice
s[0:len(s):-1]     # empty list

範囲外エラー?

驚くべきことに、 indexが範囲外のときにsliceはIndexErrorを送出しません。

インデックスが範囲外の場合、pythonは状況に応じてインデックスを0またはlen(s)に設定するようにします。例えば:

s[:len(s)+5]      # same as s[:len(s)]
s[-len(s)-5::]    # same as s[0:]
s[len(s)+5::-1]   # same as s[len(s)::-1], same as s[::-1]

3.例

例を使ってこの答えを終わらせましょう。

# create our array for demonstration
In [1]: s = [i for i in range(10)]

In [2]: s
Out[2]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

In [3]: s[2:]   # from index 2 to last index
Out[3]: [2, 3, 4, 5, 6, 7, 8, 9]

In [4]: s[:8]   # from index 0 up to index 8
Out[4]: [0, 1, 2, 3, 4, 5, 6, 7]

In [5]: s[4:7]  # from index 4(included) up to index 7(excluded)
Out[5]: [4, 5, 6]

In [6]: s[:-2]  # up to second last index(negative index)
Out[6]: [0, 1, 2, 3, 4, 5, 6, 7]

In [7]: s[-2:]  # from second last index(negative index)
Out[7]: [8, 9]

In [8]: s[::-1] # from last to first in reverse order(negative step)
Out[8]: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

In [9]: s[::-2] # all odd numbers in reversed order
Out[9]: [9, 7, 5, 3, 1]

In [11]: s[-2::-2] # all even numbers in reversed order
Out[11]: [8, 6, 4, 2, 0]

In [12]: s[3:15]   # end is out of range, python will set it to len(s)
Out[12]: [3, 4, 5, 6, 7, 8, 9]

In [14]: s[5:1]    # start > end, return empty list
Out[14]: []

In [15]: s[11]     # access index 11(greater than len(s)) will raise IndexError
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-15-79ffc22473a3> in <module>()
----> 1 s[11]

IndexError: list index out of range
25
cizixs

上記の答えは、有名なNumPyパッケージを使って可能な多次元配列スライスについては説明していません。

スライスは多次元配列にも適用できます。

# Here, a is a NumPy array

>>> a
array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
>>> a[:2, 0:3:2]
array([[1, 3],
       [5, 7]])

コンマの前の ":2"は最初の次元を操作し、コンマの後の "0:3:2"は2番目の次元を操作します。

17
Statham

私の脳はlst[start:end]start番目の項目が含まれていることを受け入れてうれしいようです。私はそれが「自然な仮定」であるとさえ言うかもしれません。

しかし時々疑問が忍び寄り、私の脳はそれがendth要素を含まないという安心感を求めます。

これらの瞬間に私はこの単純な定理に頼る:

for any n,    lst = lst[:n] + lst[n:]

このきれいなプロパティはlst[start:end]lst[end:]に含まれているのでend番目の項目を含まないことを私に教えています。

この定理はどんなnにも当てはまることに注意してください。例えば、あなたはそれをチェックすることができます

lst = range(10)
lst[:-42] + lst[-42:] == lst

Trueを返します。

13
Robert
#!/usr/bin/env python

def slicegraphical(s, lista):

    if len(s) > 9:
        print """Enter a string of maximum 9 characters,
    so the printig would looki Nice"""
        return 0;
    # print " ",
    print '  '+'+---' * len(s) +'+'
    print ' ',
    for letter in s:
        print '| {}'.format(letter),
    print '|'
    print " ",; print '+---' * len(s) +'+'

    print " ",
    for letter in range(len(s) +1):
        print '{}  '.format(letter),
    print ""
    for letter in range(-1*(len(s)), 0):
        print ' {}'.format(letter),
    print ''
    print ''


    for triada in lista:
        if len(triada) == 3:
            if triada[0]==None and triada[1] == None and triada[2] == None:
                # 000
                print s+'[   :   :   ]' +' = ', s[triada[0]:triada[1]:triada[2]]
            Elif triada[0] == None and triada[1] == None and triada[2] != None:
                # 001
                print s+'[   :   :{0:2d} ]'.format(triada[2], '','') +' = ', s[triada[0]:triada[1]:triada[2]]
            Elif triada[0] == None and triada[1] != None and triada[2] == None:
                # 010
                print s+'[   :{0:2d} :   ]'.format(triada[1]) +' = ', s[triada[0]:triada[1]:triada[2]]
            Elif triada[0] == None and triada[1] != None and triada[2] != None:
                # 011
                print s+'[   :{0:2d} :{1:2d} ]'.format(triada[1], triada[2]) +' = ', s[triada[0]:triada[1]:triada[2]]
            Elif triada[0] != None and triada[1] == None and triada[2] == None:
                # 100
                print s+'[{0:2d} :   :   ]'.format(triada[0]) +' = ', s[triada[0]:triada[1]:triada[2]]
            Elif triada[0] != None and triada[1] == None and triada[2] != None:
                # 101
                print s+'[{0:2d} :   :{1:2d} ]'.format(triada[0], triada[2]) +' = ', s[triada[0]:triada[1]:triada[2]]
            Elif triada[0] != None and triada[1] != None and triada[2] == None:
                # 110
                print s+'[{0:2d} :{1:2d} :   ]'.format(triada[0], triada[1]) +' = ', s[triada[0]:triada[1]:triada[2]]
            Elif triada[0] != None and triada[1] != None and triada[2] != None:
                # 111
                print s+'[{0:2d} :{1:2d} :{2:2d} ]'.format(triada[0], triada[1], triada[2]) +' = ', s[triada[0]:triada[1]:triada[2]]

        Elif len(triada) == 2:
            if triada[0] == None and triada[1] == None:
                # 00
                print s+'[   :   ]    ' + ' = ', s[triada[0]:triada[1]]
            Elif triada[0] == None and triada[1] != None:
                # 01
                print s+'[   :{0:2d} ]    '.format(triada[1]) + ' = ', s[triada[0]:triada[1]]
            Elif triada[0] != None and triada[1] == None:
                # 10
                print s+'[{0:2d} :   ]    '.format(triada[0]) + ' = ', s[triada[0]:triada[1]]
            Elif triada[0] != None and triada[1] != None:
                # 11
                print s+'[{0:2d} :{1:2d} ]    '.format(triada[0],triada[1]) + ' = ', s[triada[0]:triada[1]]

        Elif len(triada) == 1:
            print s+'[{0:2d} ]        '.format(triada[0]) + ' = ', s[triada[0]]


if __== '__main__':
    # Change "s" to what ever string you like, make it 9 characters for
    # better representation.
    s = 'COMPUTERS'

    # add to this list different lists to experement with indexes
    # to represent ex. s[::], use s[None, None,None], otherwise you get an error
    # for s[2:] use s[2:None]

    lista = [[4,7],[2,5,2],[-5,1,-1],[4],[-4,-6,-1], [2,-3,1],[2,-3,-1], [None,None,-1],[-5,None],[-5,0,-1],[-5,None,-1],[-1,1,-2]]

    slicegraphical(s, lista)

このスクリプトを実行して試してみることができます。以下はスクリプトから得たサンプルです。

  +---+---+---+---+---+---+---+---+---+
  | C | O | M | P | U | T | E | R | S |
  +---+---+---+---+---+---+---+---+---+
  0   1   2   3   4   5   6   7   8   9   
 -9  -8  -7  -6  -5  -4  -3  -2  -1 

COMPUTERS[ 4 : 7 ]     =  UTE
COMPUTERS[ 2 : 5 : 2 ] =  MU
COMPUTERS[-5 : 1 :-1 ] =  UPM
COMPUTERS[ 4 ]         =  U
COMPUTERS[-4 :-6 :-1 ] =  TU
COMPUTERS[ 2 :-3 : 1 ] =  MPUT
COMPUTERS[ 2 :-3 :-1 ] =  
COMPUTERS[   :   :-1 ] =  SRETUPMOC
COMPUTERS[-5 :   ]     =  UTERS
COMPUTERS[-5 : 0 :-1 ] =  UPMO
COMPUTERS[-5 :   :-1 ] =  UPMOC
COMPUTERS[-1 : 1 :-2 ] =  SEUM
[Finished in 0.9s]

否定的なステップを使用するときは、答えが1だけ右に移動することに注意してください。

13
mahmoh

Pythonでは、スライスの最も基本的な形式は次のとおりです。

l[start:end]

ここで、lは何らかのコレクション、startは包括的なインデックス、endは排他的なインデックスです。

In [1]: l = list(range(10))

In [2]: l[:5] # first five elements
Out[2]: [0, 1, 2, 3, 4]

In [3]: l[-5:] # last five elements
Out[3]: [5, 6, 7, 8, 9]

最初からスライスするときはゼロインデックスを省略でき、最後までスライスするときは冗長なので最終インデックスを省略することができます。したがって、冗長にしないでください。

In [5]: l[:3] == l[0:3]
Out[5]: True

In [6]: l[7:] == l[7:len(l)]
Out[6]: True

負の整数は、コレクションの末尾を基準にしてオフセットする場合に便利です。

In [7]: l[:-1] # include all elements but the last one
Out[7]: [0, 1, 2, 3, 4, 5, 6, 7, 8]

In [8]: l[-3:] # take the last 3 elements
Out[8]: [7, 8, 9]

次のようなスライス時に範囲外のインデックスを提供することは可能です。

In [9]: l[:20] # 20 is out of index bounds, l[20] will raise an IndexError exception
Out[9]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

In [11]: l[-20:] # -20 is out of index bounds, l[-20] will raise an IndexError exception
Out[11]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

コレクションをスライスした結果はまったく新しいコレクションであることに注意してください。さらに、割り当てにスライス表記を使用する場合、スライス割り当ての長さは同じである必要はありません。割り当てられたスライスの前後の値は保持され、コレクションは新しい値を含むように縮小または拡大されます。

In [16]: l[2:6] = list('abc') # assigning less elements than the ones contained in the sliced collection l[2:6]

In [17]: l
Out[17]: [0, 1, 'a', 'b', 'c', 6, 7, 8, 9]

In [18]: l[2:5] = list('hello') # assigning more elements than the ones contained in the sliced collection l [2:5]

In [19]: l
Out[19]: [0, 1, 'h', 'e', 'l', 'l', 'o', 6, 7, 8, 9]

開始インデックスと終了インデックスを省略すると、コレクションのコピーが作成されます。

In [14]: l_copy = l[:]

In [15]: l == l_copy and l is not l_copy
Out[15]: True

代入操作を実行するときに開始インデックスと終了インデックスが省略されると、コレクションの内容全体が参照されているもののコピーに置き換えられます。

In [20]: l[:] = list('hello...')

In [21]: l
Out[21]: ['h', 'e', 'l', 'l', 'o', '.', '.', '.']

基本的なスライスの他に、以下の表記法を適用することも可能です。

l[start:end:step]

ここで、lはコレクション、startは包括的インデックス、endは排他的インデックス、そしてstepl内のすべての nth 項目を取るために使用できるストライドです。

In [22]: l = list(range(10))

In [23]: l[::2] # take the elements which indexes are even
Out[23]: [0, 2, 4, 6, 8]

In [24]: l[1::2] # take the elements which indexes are odd
Out[24]: [1, 3, 5, 7, 9]

stepを使うことはPythonでコレクションを逆にするための役に立つトリックを提供します:

In [25]: l[::-1]
Out[25]: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

以下の例のように、stepに負の整数を使用することも可能です。

In[28]:  l[::-2]
Out[28]: [9, 7, 5, 3, 1]

ただし、stepに負の値を使用すると、混乱を招く可能性があります。さらに、Pythonicになるためには、単一スライス内でstartend、およびstepを使用しないでください。これが必要な場合は、2つの割り当て(1つはスライス用、もう1つはストライド用)でこれを行うことを検討してください。

In [29]: l = l[::2] # this step is for striding

In [30]: l
Out[30]: [0, 2, 4, 6, 8]

In [31]: l = l[1:-1] # this step is for slicing

In [32]: l
Out[32]: [2, 4, 6]
10
lmiguelvargasf

上記の回答のほとんどは、スライス表記について明確になっています。スライスに使用される拡張インデックス構文はaList[start:stop:step]の基本的な例です。

enter image description here

より多くのスライスの例: 15拡張スライス

9
Roshan Bagdiya

以下は文字列のインデックスの例です

 +---+---+---+---+---+
 | H | e | l | p | A |
 +---+---+---+---+---+
 0   1   2   3   4   5
-5  -4  -3  -2  -1

str="Name string"

スライスの例:[start:end:step]

str[start:end] # items start through end-1
str[start:]    # items start through the rest of the array
str[:end]      # items from the beginning through end-1
str[:]         # a copy of the whole array

下記は使用例です

print str[0]=N
print str[0:2]=Na
print str[0:7]=Name st
print str[0:7:2]=Nm t
print str[0:-1:2]=Nm ti
8
Prince Dhadwal

初心者向けのスライスの基本を説明するHello Worldの例を1つ追加します。とても助かりました。

6つの値['P', 'Y', 'T', 'H', 'O', 'N']を含むリストを作りましょう。

+---+---+---+---+---+---+
| P | Y | T | H | O | N |
+---+---+---+---+---+---+
  0   1   2   3   4   5 

今そのリストの最も簡単なスライスはそのサブリストです。表記は[<index>:<index>]であり、キーはこのように読むことです。

[ start cutting before this index : end cutting before this index ]

上のリストのスライス[2:5]を作ると、こうなるでしょう:

        |           |
+---+---|---+---+---|---+
| P | Y | T | H | O | N |
+---+---|---+---+---|---+
  0   1 | 2   3   4 | 5 

あなたはcut before 要素をindex 2で、もう1つのcut before 要素をindex 5で作った。その結果、これら2つのカットの間のスライス、リスト['T', 'H', 'O']になります。

6
Jeyekomon

スライス : - あなたの足の近くに蛇が現れます。見えないものから見えるものへと移動します。私たちのビジョンは(スライスのように)世界の一部だけを明らかにしています。同様に、Pythonスライスは開始と停止に基づいて要素を抽出します。私たちはPythonの多くのタイプのスライスを取ります。オプションの最初のインデックス、オプションの最後のインデックス、およびオプションのステップを指定します。

values[1:3]  Index 1 through index 3.
values[2:-1] Index 2 through index one from last.
values[:2]   Start through index 2.
values[2:]   Index 2 through end.
values[::2]  Start through end, skipping ahead 2 places each time.

あなたは以下のリンクで良い例を得ることができます: - pythonスライス記法の例

4
SHASHI BHUSAN

スライスの負のインデックスが混乱を招くと感じる場合は、これについて考えるのがとても簡単な方法です。負のインデックスをlen - indexに置き換えるだけです。たとえば、-3をlen(list) - 3に置き換えます。

スライスが内部的に何をするのかを説明する最良の方法は、この操作を実装するコードでそれを示すことです。

def slice(list, start = None, end = None, step = 1):
  # take care of missing start/end parameters
  start = 0 if start is None else start
  end = len(list) if end is None else end

  # take care of negative start/end parameters
  start = len(list) + start if start < 0 else start
  end = len(list) + end if end < 0 else end

  # now just execute for-loop with start, end and step
  return [list[i] for i in range(start, end, step)]
4
Shital Shah

私の意見では、あなたがそれを次のように見れば、あなたはPython文字列スライス記法をもっとよく理解し記憶するでしょう(読んでください)。

次の文字列で作業しましょう...

azString = "abcdefghijklmnopqrstuvwxyz"

知らない人のために、azString[x:y]という表記法を使ってazStringname__から任意の部分文字列を作成することができます。

他のプログラミング言語から来て、それは常識が危うくなるときです。 xとyは何ですか?

私はxとyが何であるかを思い出し、最初の試みで文字列を適切にスライスするのを手助けする暗記テクニックを探すために座っていくつかのシナリオを実行する必要がありました。

私の結論は、xとyは、追加したい文字列を囲む境界インデックスと見なすべきだということです。そのため、式はazString[index1, index2]として、またはもっと明確にazString[index_of_first_character, index_after_the_last_character]として見るべきです。

これはその視覚化の例です...

Letters   a b c d e f g h i j ...
         ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ 
Indexes  0 1 2 3 4 5 6 7 8 9 ... 
             |           |
cdefgh    index1       index2

したがって、index1とindex2を目的の部分文字列を囲む値に設定するだけで済みます。たとえば、サブストリング "cdefgh"を取得するには、 "c"の左側のインデックスが2で、右側のサイズ "h"のインデックスが8であるため、azString[2:8]を使用できます。

境界を設定していることを忘れないでください。そして、これらの境界は、このように部分文字列を囲む大括弧を配置できる位置です。

a b [ c d e f g h ] i j

そのトリックはずっと働いていて、暗記するのは簡単です。

4
asiby

基本的なスライス手法は、始点、終点、およびステップサイズを定義することです - ストライドとも呼ばれます。

まず、スライスに使用する値のリストを作成します。

スライスする2つのリストを作成します。最初のリストは1から9までの数値リストです(リストA)。 2番目も0から9までの数値リストです(リストB)

A = list(range(1,10,1)) # start,stop,step
B = list(range(9))

print("This is List A:",A)
print("This is List B:",B)

Aから3、Bから6の番号を付けます。

print(A[2])
print(B[6])

基本スライス

スライスに使用される拡張インデックス構文は、aList [start:stop:step]です。 start引数とstep引数はどちらもデフォルトのnoneに設定されています。唯一の必須引数はstopです。これは、リストAとBを定義するためにrangeがどのように使用されたかに似ていることに気付きましたか?これは、スライスオブジェクトがrange(start、stop、step)で指定されたインデックスのセットを表すためです。 Python 3.4のドキュメント

ご覧のとおり、stopだけを定義すると1つの要素が返されます。開始時のデフォルトはnoneなので、これは1つの要素のみを取得することになります。

最初の要素はインデックス1ではなくインデックス0です。これが、この演習で2つのリストを使用している理由です。リストAの要素は序数の順序に従って番号が付けられます(最初の要素は1、2番目の要素は2など)、リストBの要素はそれらをインデックス付けするのに使用される番号です(最初の要素0は[0]など)。 ).

拡張インデックス構文では、さまざまな値を取得します。たとえば、すべての値はコロンで検索されます。

A[:]

要素のサブセットを取得するには、開始位置と終了位置を定義する必要があります。

パターンaList [start:stop]を指定して、リストAから最初の2つの要素を取得します。

3

スライシングをインデックスを与えるrangeに関連付けることができるかどうか理解するのは簡単です。スライスを次の2つのカテゴリに分類できます。


1.ステップなし、またはステップ>0。たとえば、[i:j]または[i:j:k](k> 0)

シーケンスがs=[1,2,3,4,5]であるとします。

  • 0<i<len(s)0<j<len(s)の場合、[i:j:k] -> range(i,j,k)

例えば、[0:3:2] -> range(0,3,2) -> 0, 2

  • i>len(s)またはj>len(s)の場合はi=len(s)またはj=len(s)

例えば、[0:100:2] -> range(0,len(s),2) -> range(0,5,2) -> 0, 2, 4

  • i<0またはj<0の場合、i=max(0,len(s)+i)またはj=max(0,len(s)+j)

例えば、[0:-3:2] -> range(0,len(s)-3,2) -> range(0,2,2) -> 0

別の例としては、[0:-1:2] -> range(0,len(s)-1,2) -> range(0,4,2) -> 0, 2

  • iが指定されていない場合、i=0

例えば、[:4:2] -> range(0,4,2) -> range(0,4,2) -> 0, 2

  • jが指定されていない場合、j=len(s)

例えば、[0::2] -> range(0,len(s),2) -> range(0,5,2) -> 0, 2, 4


2.ステップ<0。例えば、[i:j:k](k <0)

シーケンスがs=[1,2,3,4,5]であるとします。

  • 0<i<len(s)0<j<len(s)の場合、[i:j:k] -> range(i,j,k)

例えば、[5:0:-2] -> range(5,0,-2) -> 5, 3, 1

  • i>len(s)またはj>len(s)の場合はi=len(s)-1またはj=len(s)-1

例えば、[100:0:-2] -> range(len(s)-1,0,-2) -> range(4,0,-2) -> 4, 2

  • i<0またはj<0の場合、i=max(-1,len(s)+i)またはj=max(-1,len(s)+j)

例えば、[-2:-10:-2] -> range(len(s)-2,-1,-2) -> range(3,-1,-2) -> 3, 1

  • iが指定されていない場合、i=len(s)-1

例えば、[:0:-2] -> range(len(s)-1,0,-2) -> range(4,0,-2) -> 4, 2

  • jが指定されていない場合、j=-1

例えば、[2::-2] -> range(2,-1,-2) -> 2, 0

別の例としては、[::-1] -> range(len(s)-1,-1,-1) -> range(4,-1,-1) -> 4, 3, 2, 1, 0


要約すれば

enter image description here

1
Banghua Zhao

オンラインソース、またはスライシングの正確な内容を説明するPythonドキュメントが見つからないことに少しイライラしました。

アーロンホールの提案を受けて、CPythonソースコードの関連部分を読んでから、CPythonでの方法と同様にスライスを実行するPythonコードを作成しました。私はPython 3のコードを整数リストの数百万のランダムテストでテストしました。

私のコードで、CPythonの関連する関数への参照が役立つ場合があります。

# return the result of slicing list x
# See the part of list_subscript() in listobject.c that pertains
# to when the indexing item is a PySliceObject
def slicer(x, start=None, stop=None, step=None):
    # Handle slicing index values of None, and a step value of 0.
    # See PySlice_Unpack() in sliceobject.c, which
    # extracts start, stop, step from a PySliceObject.
    maxint = 10000000       # a hack to simulate PY_SSIZE_T_MAX
    if step == None:
        step = 1
    Elif step == 0:
        raise ValueError('slice step cannot be zero')

    if start == None:
        start = maxint if step < 0 else 0
    if stop == None:
        stop = -maxint if step < 0 else maxint

    # Handle negative slice indexes and bad slice indexes.
    # Compute number of elements in the slice as slice_length.
    # See PySlice_AdjustIndices() in sliceobject.c
    length = len(x)
    slice_length = 0

    if start < 0:
        start += length
        if start < 0:
            start = -1 if step < 0 else 0
    Elif start >= length:
        start = length - 1 if step < 0 else length

    if stop < 0:
        stop += length
        if stop < 0:
            stop = -1 if step < 0 else 0
    Elif stop > length:
        stop = length - 1 if step < 0 else length

    if step < 0:
        if stop < start:
            slice_length = (start - stop - 1) // (-step) + 1
    else: 
        if start < stop:
            slice_length = (stop - start - 1) // step + 1

    # cases of step = 1 and step != 1 are treated separately
    if slice_length <= 0:
        return []
    Elif step == 1:
        # see list_slice() in listobject.c
        result = []
        for i in range(stop - start):
            result.append(x[i+start])
        return result
    else:
        result = []
        cur = start
        for i in range(slice_length):
            result.append(x[cur])
            cur += step
        return result
1
grbruns

私は Pythonチュートリアル の図(他のさまざまな答えで引用されている)がこのストライドがポジティブストライドに役立つとしてはうまくいくとは思わないが、ネガティブストライドにはならない。

これがダイアグラムです:

 +---+---+---+---+---+---+
 | P | y | t | h | o | n |
 +---+---+---+---+---+---+
 0   1   2   3   4   5   6
-6  -5  -4  -3  -2  -1

図から、私はa[-4,-6,-1]yPであることを期待しますが、それはtyです。

>>> a = "Python"
>>> a[2:4:1] # as expected
'th'
>>> a[-4:-6:-1] # off by 1
'ty'

常にうまくいくのは、文字またはスロットを考慮し、インデックスを半開区間として使用することです - 正のストライドの場合は右開き、負のストライドの場合は左開きです。

このように、私はインターバル用語でa[-4:-6:-1]a(-6,-4]と考えることができます。

 +---+---+---+---+---+---+
 | P | y | t | h | o | n |
 +---+---+---+---+---+---+
   0   1   2   3   4   5  
  -6  -5  -4  -3  -2  -1

 +---+---+---+---+---+---+---+---+---+---+---+---+
 | P | y | t | h | o | n | P | y | t | h | o | n |
 +---+---+---+---+---+---+---+---+---+---+---+---+
  -6  -5  -4  -3  -2  -1   0   1   2   3   4   5  
0
aguadopd

私は個人的にそれをforループのように考えています

a[start:end:step]    
# for(i = start; i < end; i += step)

また、startおよびendの負の値は、リストの末尾を基準にしていることに注意してください。

0
Raman