Memahami notasi slice

3285

Saya perlu penjelasan yang baik (referensi adalah nilai tambah) pada notasi irisan Python.

Bagi saya, notasi ini perlu sedikit diambil.

Kelihatannya sangat kuat, tapi saya belum mengerti.

Simon
sumber

Jawaban:

4508

Ini benar-benar sangat sederhana:

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

Ada juga stepnilainya, yang dapat digunakan dengan salah satu di atas:

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

Poin utama yang perlu diingat adalah bahwa :stopnilai tersebut mewakili nilai pertama yang tidak ada dalam slice yang dipilih. Jadi, perbedaan antara stopdan startjumlah elemen yang dipilih (jikastep 1, default).

Fitur lainnya adalah angka itu startatau stopmungkin angka negatif , yang artinya dihitung dari akhir array bukan dari awal. Begitu:

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

Demikian pula, stepmungkin angka negatif:

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 baik kepada programmer jika ada item lebih sedikit dari yang Anda minta. Misalnya, jika Anda meminta a[:-2]dan ahanya berisi satu elemen, Anda mendapatkan daftar kosong dan bukan kesalahan. Terkadang Anda lebih suka kesalahan, jadi Anda harus sadar bahwa ini mungkin terjadi.

Hubungan dengan slice()objek

Operator slicing []sebenarnya digunakan dalam kode di atas dengan slice()objek menggunakan :notasi (yang hanya valid di dalam []), yaitu:

a[start:stop:step]

setara dengan:

a[slice(start, stop, step)]

Objek slice juga berperilaku sedikit berbeda tergantung pada jumlah argumen, mirip dengan range(), yaitu keduanya slice(stop)dan slice(start, stop[, step])didukung. Untuk melewati menentukan argumen yang diberikan, orang mungkin menggunakan None, sehingga misalnya a[start:]setara dengan a[slice(start, None)]atau a[::-1]setara dengan a[slice(None, None, -1)].

Sementara :notasi berbasis-sangat membantu untuk mengiris sederhana, penggunaan eksplisit slice()objek menyederhanakan generasi pemrograman pemotongan.

Greg Hewgill
sumber
122
Mengiris tipe builtin mengembalikan salinan tetapi itu tidak universal. Khususnya, mengiris array NumPy mengembalikan tampilan yang berbagi memori dengan yang asli.
Beni Cherniavsky-Paskin
43
Ini adalah jawaban yang indah dengan suara untuk membuktikannya, tetapi itu melewatkan satu hal: Anda dapat menggantikan Noneruang kosong mana pun. Misalnya [None:None]membuat salinan lengkap. Ini berguna ketika Anda perlu menentukan akhir rentang menggunakan variabel dan perlu memasukkan item terakhir.
Mark Ransom
6
Yang benar-benar mengganggu saya adalah bahwa python mengatakan bahwa ketika Anda tidak mengatur awal dan akhir, defaultnya adalah 0 dan panjang urutan. Jadi, secara teori, ketika Anda menggunakan "abcdef" [:: - 1] itu harus diubah menjadi "abcdef" [0: 6: -1], tetapi kedua ekspresi ini tidak mendapatkan output yang sama. Saya merasa ada sesuatu yang hilang dalam dokumentasi python sejak pembuatan bahasa.
axell13
6
Dan saya tahu bahwa "abcdef" [:: - 1] ditransformasikan menjadi "abcdef" [6: -7: -1], jadi, cara terbaik untuk menjelaskannya adalah: biarkan len menjadi panjang urutannya. Jika langkah positif , default untuk awal dan akhir adalah 0 dan len . Jika langkah negatif , default untuk awal dan akhir adalah len dan - len - 1.
axell13
4
Karena stackoverflow.com/questions/39241529/... ditandai sebagai dupe dari ini, apakah masuk akal untuk menambahkan bagian dengan apa yang delnotasi irisan slt. Secara khusus, del arr[:]tidak segera jelas ("arr [:] membuat salinan, begitu juga menghapus del salinan itu ???" dll.)
khazhyk
538

The Python tutorial berbicara tentang hal itu (scroll ke bawah sedikit sampai Anda mendapatkan ke bagian tentang mengiris).

Diagram seni ASCII juga membantu untuk mengingat cara kerja irisan:

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

Salah satu cara untuk mengingat bagaimana irisan bekerja adalah dengan memikirkan indeks sebagai menunjuk di antara karakter, dengan tepi kiri karakter pertama bernomor 0. Kemudian tepi kanan karakter terakhir dari string n karakter memiliki indeks n .

Hans Nowak
sumber
10
Saran ini berfungsi untuk langkah positif, tetapi tidak untuk langkah negatif. Dari diagram, saya berharap a[-4,-6,-1]untuk menjadi yPtetapi ty. Yang selalu berhasil adalah berpikir dalam karakter atau slot dan menggunakan pengindeksan sebagai interval setengah terbuka - kanan-terbuka jika langkah positif, kiri-terbuka jika langkah negatif.
aguadopd
Tetapi tidak ada cara untuk runtuh ke set kosong mulai dari akhir (seperti x[:0]halnya ketika mulai dari awal), jadi Anda harus array kasus kecil khusus. : /
endolith
412

Menghitung kemungkinan yang diizinkan oleh tata bahasa:

>>> 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]]

Tentu saja, jika (high-low)%stride != 0, maka titik akhirnya akan sedikit lebih rendah darihigh-1 .

Jika stridenegatif, pemesanan berubah sedikit karena kami menghitung mundur:

>>> 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]]

Pengiris yang diperluas (dengan koma dan elips) sebagian besar hanya digunakan oleh struktur data khusus (seperti NumPy); urutan dasar tidak mendukungnya.

>>> class slicee:
...     def __getitem__(self, item):
...         return repr(item)
...
>>> slicee()[0, 1:2, ::5, ...]
'(0, slice(1, 2, None), slice(None, None, 5), Ellipsis)'
singkat
sumber
Sebenarnya masih ada sesuatu yang tertinggal misalnya jika saya mengetik 'apel' [4: -4: -1] Saya mendapatkan 'elp', python menerjemahkan -4 ke 1 mungkin?
liyuan
perhatikan bahwa backticks tidak digunakan lagirepr
wjandrea
@liyuan Tipe implementasinya __getitem__adalah; contoh Anda setara dengan apple[slice(4, -4, -1)].
chepner
320

Jawaban di atas tidak membahas penugasan slice. Untuk memahami penugasan slice, sebaiknya tambahkan konsep lain pada seni 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']

Satu heuristik adalah, untuk irisan dari nol ke n, pikirkan: "nol adalah awal, mulailah dari awal dan ambil n item dalam daftar".

>>> 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']

Heuristik lain adalah, "untuk setiap irisan, ganti start dengan nol, terapkan heuristik sebelumnya untuk mendapatkan akhir daftar, lalu hitung angka pertama kembali untuk memotong item dari awal"

>>> 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.

Aturan pertama penugasan slice adalah bahwa sejak slicing mengembalikan daftar, penugasan slice membutuhkan daftar (atau yang dapat diubah lainnya):

>>> 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

Aturan kedua penugasan slice, yang juga bisa Anda lihat di atas, adalah bahwa bagian apa pun dari daftar dikembalikan oleh pengindeksan slice, itu adalah bagian yang sama yang diubah oleh penugasan slice:

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

Aturan penugasan slice yang ketiga adalah, daftar yang ditugaskan (iterable) tidak harus memiliki panjang yang sama; irisan diindeks hanya diiris dan diganti secara massal oleh apa pun yang ditugaskan:

>>> 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']

Bagian tersulit yang digunakan adalah penugasan irisan kosong. Dengan menggunakan heuristik 1 dan 2, Anda dapat dengan mudah mengindeks potongan kosong:

>>> 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]
 []

Dan setelah Anda melihat itu, penugasan slice ke slice kosong juga masuk akal:

>>> 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

Perhatikan bahwa, karena kita tidak mengubah angka kedua dari slice (4), item yang dimasukkan selalu menumpuk tepat di atas 'o', bahkan ketika kita sedang menetapkan slice kosong. Jadi posisi untuk tugas irisan kosong adalah perpanjangan logis dari posisi untuk tugas irisan irisan kosong.

Membackup sedikit, apa yang terjadi ketika Anda terus dengan prosesi kami menghitung awal irisan?

>>> 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]
 []

Dengan mengiris, setelah selesai, Anda selesai; itu tidak mulai mengiris ke belakang. Dalam Python Anda tidak mendapatkan langkah negatif kecuali jika Anda secara eksplisit meminta mereka dengan menggunakan angka negatif.

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

Ada beberapa konsekuensi aneh terhadap aturan "setelah selesai, selesai":

>>> 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

Bahkan, dibandingkan dengan pengindeksan, pengiris Python adalah kesalahan-bukti yang aneh:

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

Terkadang hal ini berguna, tetapi juga dapat menyebabkan perilaku yang agak aneh:

>>> 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']

Tergantung pada aplikasi Anda, itu mungkin ... atau mungkin tidak ... menjadi apa yang Anda harapkan di sana!


Di bawah ini adalah teks dari jawaban asli saya. Ini bermanfaat bagi banyak orang, jadi saya tidak ingin menghapusnya.

>>> 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]

Ini juga dapat memperjelas perbedaan antara pengirisan dan pengindeksan.

David M. Perlman
sumber
246

Jelaskan notasi irisan Python

Singkatnya, titik dua ( :) dalam notasi subscript ( subscriptable[subscriptarg]) make slice notasi - yang memiliki argumen opsional, start, stop, step:

sliceable[start:stop:step]

Mengiris Python adalah cara komputasi yang cepat untuk secara metodis mengakses bagian data Anda. Menurut pendapat saya, untuk menjadi programmer Python tingkat menengah, ini adalah salah satu aspek dari bahasa yang perlu Anda ketahui.

Definisi Penting

Untuk memulainya, mari kita tentukan beberapa istilah:

mulai: indeks awal dari slice, itu akan mencakup elemen pada indeks ini kecuali itu sama dengan berhenti , default ke 0, yaitu indeks pertama. Jika negatif, artinya memulain item dari akhir.

berhenti: indeks akhir dari slice, tidak termasuk elemen pada indeks ini, default untuk panjang urutan yang diiris, yaitu, hingga dan termasuk akhir.

langkah: jumlah kenaikan indeks, default ke 1. Jika negatif, Anda mengiris iterable secara terbalik.

Cara Pengindeksan Bekerja

Anda dapat membuat angka positif atau negatif ini. Arti bilangan positif itu langsung, tetapi untuk bilangan negatif, seperti halnya indeks dalam Python, Anda menghitung mundur dari ujung untuk memulai dan berhenti , dan untuk langkah ini , Anda cukup mengurangi indeks Anda. Contoh ini dari tutorial dokumentasi , tetapi saya telah sedikit memodifikasinya untuk menunjukkan item mana dalam urutan masing-masing referensi indeks:

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

Cara Mengiris Bekerja

Untuk menggunakan notasi irisan dengan urutan yang mendukungnya, Anda harus menyertakan setidaknya satu titik dua dalam tanda kurung siku yang mengikuti urutan (yang sebenarnya menerapkan __getitem__metode urutan, sesuai dengan model data Python .)

Notasi slice berfungsi seperti ini:

sequence[start:stop:step]

Dan ingat bahwa ada default untuk start , stop , dan step , jadi untuk mengakses default, cukup tinggalkan argumen.

Notasi irisan untuk mendapatkan sembilan elemen terakhir dari daftar (atau urutan lainnya yang mendukungnya, seperti string) akan terlihat seperti ini:

my_list[-9:]

Ketika saya melihat ini, saya membaca bagian dalam tanda kurung sebagai "kesembilan dari akhir, sampai akhir." (Sebenarnya, saya menyingkatnya secara mental sebagai "-9, pada")

Penjelasan:

Notasi lengkapnya adalah

my_list[-9:None:None]

dan untuk mengganti default (sebenarnya ketika stepnegatif, stopdefault adalah -len(my_list) - 1, jadi Noneuntuk stop benar-benar berarti pergi ke mana pun langkah akhir membawanya ke):

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

Tanda titik dua ,, :adalah yang memberi tahu Python bahwa Anda memberinya sepotong dan bukan indeks biasa. Itulah sebabnya cara idiomatis membuat salinan daftar yang dangkal di Python 2 adalah

list_copy = sequence[:]

Dan membersihkannya adalah dengan:

del my_list[:]

(Python 3 mendapat list.copydan list.clearmetode.)

Ketika stepnegatif, standar untuk startdan stopberubah

Secara default, ketika stepargumen kosong (atau None), itu ditugaskan untuk +1.

Tetapi Anda bisa memasukkan bilangan bulat negatif, dan daftar (atau sebagian besar slicables standar lainnya) akan diiris dari ujung ke awal.

Dengan demikian irisan negatif akan mengubah default untuk startdanstop !

Mengkonfirmasi ini di sumbernya

Saya ingin mendorong pengguna untuk membaca sumber serta dokumentasi. The kode sumber untuk sepotong objek dan logika ini ditemukan di sini . Pertama-tama kita menentukan apakah stepnegatif:

 step_is_negative = step_sign < 0;

Jika demikian, batas bawah -1 berarti kita mengiris hingga dan termasuk awal, dan batas atas adalah panjang minus 1, artinya kita mulai dari akhir. (Perhatikan bahwa semantik ini -1adalah berbeda dari -1yang pengguna dapat lulus indeks Python menunjukkan item terakhir.)

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

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

Kalau steptidak positif, dan batas bawah akan menjadi nol dan batas atas (yang kita naiki tetapi tidak termasuk) panjang daftar irisan.

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

Kemudian, kita mungkin perlu menerapkan default untuk startdan stop- default maka untuk startdihitung sebagai batas atas ketika stepnegatif:

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

dan stop, batas bawah:

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

Berikan iris Anda nama deskriptif!

Anda mungkin merasa berguna untuk memisahkan pembentukan irisan dari meneruskannya ke list.__getitem__metode ( itulah yang dilakukan kurung siku ). Sekalipun Anda bukan orang baru, itu membuat kode Anda lebih mudah dibaca sehingga orang lain yang mungkin harus membaca kode Anda dapat lebih mudah memahami apa yang Anda lakukan.

Namun, Anda tidak bisa hanya menetapkan beberapa bilangan bulat yang dipisahkan oleh titik dua ke sebuah variabel. Anda perlu menggunakan objek slice:

last_nine_slice = slice(-9, None)

Argumen kedua,, Nonediperlukan, sehingga argumen pertama ditafsirkan sebagai startargumen jika tidak maka akan menjadi stopargumen .

Anda kemudian dapat meneruskan objek irisan ke urutan Anda:

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

Sangat menarik bahwa rentang juga mengambil irisan:

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

Pertimbangan Memori:

Karena irisan daftar Python membuat objek baru dalam memori, fungsi penting lainnya yang harus diperhatikan adalah itertools.islice. Biasanya Anda ingin mengulang lebih dari satu irisan, tidak hanya itu dibuat secara statis dalam memori. islicesempurna untuk ini. Peringatan, itu tidak mendukung argumen negatif untuk start,, stopatau step, jadi jika itu masalah Anda mungkin perlu menghitung indeks atau membalikkan iterable terlebih dahulu.

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

dan sekarang:

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

Fakta bahwa irisan daftar membuat salinan adalah fitur dari daftar itu sendiri. Jika Anda mengiris objek canggih seperti DataFrame Pandas, itu dapat mengembalikan tampilan pada aslinya, dan bukan salinan.

Aaron Hall
sumber
147

Dan beberapa hal yang tidak langsung jelas bagi saya ketika saya pertama kali melihat sintaksis slicing:

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

Cara mudah untuk membalik urutan!

Dan jika Anda ingin, untuk beberapa alasan, setiap item kedua dalam urutan terbalik:

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

Dalam Python 2.7

Mengiris dengan 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).

Memahami penugasan indeks sangat penting.

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

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

Ketika Anda mengatakan [a: b: c], Anda mengatakan tergantung pada tanda c (maju atau mundur), mulai dari dan berakhir pada b (tidak termasuk elemen pada indeks ke-b). Gunakan aturan pengindeksan di atas dan ingat Anda hanya akan menemukan elemen dalam rentang ini:

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

Namun rentang ini berlanjut di kedua arah tanpa batas:

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

Sebagai contoh:

             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

Jika pilihan a, b, dan c Anda memungkinkan tumpang tindih dengan rentang di atas saat Anda melintasi menggunakan aturan untuk a, b, c di atas Anda akan mendapatkan daftar dengan elemen (disentuh saat melintasi) atau Anda akan mendapatkan daftar kosong.

Satu hal terakhir: jika a dan b sama, maka Anda juga mendapatkan daftar kosong:

>>> 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]
Ankur Agarwal
sumber
2
satu lagi contoh menarik: a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]; a[:-2:-2]yang menghasilkan[9]
Deviacium
96

Temukan tabel hebat ini di 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)
AdrianoFerrari
sumber
65

Setelah menggunakannya sedikit saya menyadari bahwa deskripsi yang paling sederhana adalah persis sama dengan argumen dalam satu forlingkaran ...

(from:to:step)

Semua dari mereka adalah opsional:

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

Kemudian pengindeksan negatif hanya perlu Anda menambahkan panjang string ke indeks negatif untuk memahaminya.

Ini tetap bekerja untuk saya ...

Simon
sumber
52

Saya merasa lebih mudah untuk mengingat cara kerjanya, dan kemudian saya bisa mengetahui kombinasi start / stop / step tertentu.

Ini penting untuk dipahami range()terlebih dahulu:

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

Mulai dari start, selangkah demi selangkah step, jangan sampai stop. Sangat sederhana.

Yang perlu diingat tentang langkah negatif adalah bahwa stopselalu merupakan akhir yang dikecualikan, apakah itu lebih tinggi atau lebih rendah. Jika Anda ingin irisan yang sama dalam urutan yang berlawanan, itu jauh lebih bersih untuk melakukan pembalikan secara terpisah: misal 'abcde'[1:-2][::-1]mengiris satu char dari kiri, dua dari kanan, lalu membalikkan. (Lihat juga reversed().)

Mengiris urutan adalah sama, kecuali itu pertama menormalkan indeks negatif, dan itu tidak pernah bisa keluar dari urutan:

TODO : Kode di bawah ini memiliki bug dengan "tidak pernah keluar dari urutan" ketika abs (langkah)> 1; Saya pikir saya menambalnya menjadi benar, tetapi sulit dimengerti.

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]

Jangan khawatir tentang is Nonedetailnya - ingat saja bahwa menghilangkan startdan / atau stopselalu melakukan hal yang benar untuk memberi Anda seluruh urutan.

Normalisasi indeks negatif pertama memungkinkan mulai dan / atau berhenti dihitung dari akhir secara independen: 'abcde'[1:-2] == 'abcde'[1:3] == 'bc'meskipun range(1,-2) == []. Normalisasi kadang-kadang dianggap sebagai "modulo the length", tetapi perhatikan itu menambahkan panjang hanya sekali: misalnya 'abcde'[-53:42]hanya seluruh string.

Beni Cherniavsky-Paskin
sumber
3
Ini this_is_how_slicing_workstidak sama dengan irisan python. EG [0, 1, 2][-5:3:3]akan mendapatkan [0] dengan python, tetapi list(this_is_how_slicing_works([0, 1, 2], -5, 3, 3))mendapatkan [1].
Eastsun
@ Eastsun Ups, kau benar! Kasus yang lebih jelas: range(4)[-200:200:3] == [0, 3]tetapi list(this_is_how_slicing_works([0, 1, 2, 3], -200, 200, 3)) == [2]. Saya if 0 <= i < len(seq):adalah upaya untuk mengimplementasikan "tidak pernah keluar dari urutan" secara sederhana tetapi salah untuk langkah> 1. Saya akan menulis ulang nanti hari ini (dengan tes).
Beni Cherniavsky-Paskin
40

Saya menggunakan metode "indeks poin antar elemen" untuk memikirkannya sendiri, tetapi salah satu cara menggambarkannya yang terkadang membantu orang lain mendapatkannya adalah ini:

mylist[X:Y]

X adalah indeks dari elemen pertama yang Anda inginkan.
Y adalah indeks dari elemen pertama yang tidak Anda inginkan.

Steve Losh
sumber
40
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   :
|--------------->
    <---------------|

Saya harap ini akan membantu Anda untuk membuat model daftar dengan Python.

Referensi: http://wiki.python.org/moin/MovingToPythonFromOtherLanguages

Xiaoyu
sumber
38

Notasi pengiris Python:

a[start:end:step]
  • Untuk startdan end, nilai-nilai negatif ditafsirkan sebagai relatif terhadap akhir urutan.
  • Indeks positif untuk endmenunjukkan posisi setelah elemen terakhir dimasukkan.
  • Nilai-nilai kosong yang gagal sebagai berikut: [+0:-0:1].
  • Menggunakan langkah negatif membalikkan interpretasi startdanend

Notasi meluas ke matriks (numpy) dan array multidimensi. Misalnya, untuk mengiris seluruh kolom yang dapat Anda gunakan:

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

Irisan menyimpan referensi, bukan salinan, dari elemen array. Jika Anda ingin membuat salinan array secara terpisah, Anda dapat menggunakan deepcopy().

bangsawan
sumber
34

Anda juga dapat menggunakan tugas irisan untuk menghapus satu atau lebih elemen dari daftar:

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

Ini hanya untuk beberapa info tambahan ... Pertimbangkan daftar di bawah ini

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

Beberapa trik lain untuk membalik daftar:

>>> 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]
Arindam Roychowdhury
sumber
33

Ini adalah bagaimana saya mengajarkan irisan kepada pemula:

Memahami perbedaan antara pengindeksan dan pengirisan:

Wiki Python memiliki gambar yang luar biasa ini yang dengan jelas membedakan pengindeksan dan pengirisan.

Masukkan deskripsi gambar di sini

Ini adalah daftar dengan enam elemen di dalamnya. Untuk memahami cara mengiris dengan lebih baik, pertimbangkan daftar itu sebagai satu set enam kotak yang ditempatkan bersama. Setiap kotak memiliki alfabet di dalamnya.

Pengindeksan seperti berurusan dengan isi kotak. Anda dapat memeriksa isi kotak apa pun. Tetapi Anda tidak dapat memeriksa isi beberapa kotak sekaligus. Anda bahkan dapat mengganti isi kotak. Tetapi Anda tidak bisa menempatkan dua bola dalam satu kotak atau mengganti dua bola sekaligus.

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

Mengiris seperti berurusan dengan kotak sendiri. Anda dapat mengambil kotak pertama dan meletakkannya di meja lain. Untuk mengambil kotak, yang perlu Anda ketahui adalah posisi awal dan akhir kotak.

Anda bahkan dapat mengambil tiga kotak pertama atau dua kotak terakhir atau semua kotak antara 1 dan 4. Jadi, Anda dapat memilih satu set kotak jika Anda tahu awal dan akhir. Posisi ini disebut posisi start dan stop.

Yang menarik adalah Anda bisa mengganti beberapa kotak sekaligus. Anda juga dapat menempatkan beberapa kotak di mana pun Anda suka.

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']

Mengiris dengan Langkah:

Sampai sekarang Anda telah memilih kotak secara terus menerus. Tetapi kadang-kadang Anda perlu mengambil dengan hati-hati. Misalnya, Anda dapat mengambil setiap kotak kedua. Anda bahkan dapat mengambil setiap kotak ketiga dari ujung. Nilai ini disebut ukuran langkah. Ini menunjukkan jarak antara pickup Anda yang berurutan. Ukuran langkah harus positif jika Anda memilih kotak dari awal hingga akhir dan sebaliknya.

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]: []

Bagaimana Python Angka Keluar Parameter Hilang:

Saat mengiris, jika Anda mengabaikan parameter apa pun, Python mencoba mengetahuinya secara otomatis.

Jika Anda memeriksa kode sumber CPython , Anda akan menemukan fungsi yang disebut PySlice_GetIndicesEx () yang menggambarkan indeks ke slice untuk parameter yang diberikan. Berikut adalah kode yang ekuivalen secara logis dengan Python.

Fungsi ini mengambil objek Python dan parameter opsional untuk mengiris dan mengembalikan panjang mulai, berhenti, langkah, dan iris untuk irisan yang diminta.

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)

Ini adalah kecerdasan yang ada di balik irisan. Karena Python memiliki fungsi bawaan yang disebut slice, Anda dapat melewati beberapa parameter dan memeriksa seberapa pintar menghitung parameter yang hilang.

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]

Catatan: Posting ini awalnya ditulis di blog saya, The Intelligence Behind Python Slices .

ChillarAnand
sumber
29

Sebagai aturan umum, menulis kode dengan banyak nilai indeks yang dikodekan menyebabkan kekacauan pembacaan dan pemeliharaan. Misalnya, jika Anda kembali ke kode setahun kemudian, Anda akan melihatnya dan bertanya-tanya apa yang Anda pikirkan ketika Anda menulisnya. Solusi yang ditampilkan hanyalah cara yang lebih jelas menyatakan apa yang sebenarnya dilakukan kode Anda. Secara umum, built-in slice () membuat objek slice yang dapat digunakan di mana pun slice diperbolehkan. Sebagai contoh:

>>> 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]

Jika Anda memiliki turunan slice s, Anda dapat memperoleh informasi lebih lanjut tentangnya dengan melihat masing-masing atribut s.start, s.stop, dan s.step. Sebagai contoh:

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

1. Notasi Iris

Untuk membuatnya sederhana, ingat irisan hanya memiliki satu bentuk:

s[start:end:step]

dan inilah cara kerjanya:

  • s: sebuah objek yang dapat diiris
  • start: indeks pertama untuk memulai iterasi
  • end: indeks terakhir, CATATAN endindeks yang tidak akan dimasukkan dalam irisan yang dihasilkan
  • step: pilih elemen setiap stepindeks

Hal lain yang impor: semua start, end, stepbisa dihilangkan! Dan jika mereka dihilangkan, nilai default mereka akan digunakan: 0, len(s),1 sesuai.

Jadi kemungkinan variasi adalah:

# 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[:]

CATATAN: Jika start >= end(hanya mempertimbangkan saat step>0), Python akan mengembalikan potongan kosong[] .

2. Perangkap

Bagian di atas menjelaskan fitur inti tentang cara kerja slice, dan itu akan berfungsi pada sebagian besar kesempatan. Namun, mungkin ada jebakan yang harus Anda perhatikan, dan bagian ini menjelaskannya.

Indeks negatif

Hal pertama yang membingungkan pelajar Python adalah bahwa indeks bisa negatif! Jangan panik: indeks negatif berarti menghitung mundur.

Sebagai contoh:

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

Langkah negatif

Membuat hal-hal lebih membingungkan adalah itu stepbisa negatif juga!

Langkah negatif berarti mengembalikan array ke belakang: dari ujung ke awal, dengan indeks akhir disertakan, dan indeks awal dikecualikan dari hasilnya.

CATATAN : ketika langkah negatif, nilai default untuk startadalah len(s)(sementara endtidak sama dengan 0, karena s[::-1]berisi s[0]). Sebagai contoh:

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

Kesalahan di luar jangkauan?

Terkejut: irisan tidak meningkatkan IndexError ketika indeks berada di luar jangkauan!

Jika indeks berada di luar jangkauan, Python akan mencoba yang terbaik untuk mengatur indeks ke 0atau len(s)sesuai dengan situasi. Sebagai contoh:

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

3. Contoh

Mari kita selesaikan jawaban ini dengan contoh, menjelaskan semua yang telah kita diskusikan:

# 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, and 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 an IndexError
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-15-79ffc22473a3> in <module>()
----> 1 s[11]

IndexError: list index out of range
cizixs
sumber
24

Jawaban sebelumnya tidak membahas pemotongan multi-dimensi array yang dimungkinkan menggunakan paket NumPy yang terkenal :

Mengiris juga dapat diterapkan ke array multi-dimensi.

# 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" Sebelum koma beroperasi pada dimensi pertama dan " 0:3:2" setelah koma beroperasi pada dimensi kedua.

Statham
sumber
4
Hanya pengingat ramah bahwa Anda tidak bisa melakukan ini dengan Python listtetapi hanya di arraydalam Numpy
Mars Lee
15
#!/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 __name__ == '__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)

Anda dapat menjalankan skrip ini dan bereksperimen dengannya, di bawah ini adalah beberapa contoh yang saya dapatkan dari skrip.

  +---+---+---+---+---+---+---+---+---+
  | 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]

Saat menggunakan langkah negatif, perhatikan bahwa jawabannya digeser ke kanan oleh 1.

mahmoh
sumber
14

Otak saya sepertinya senang menerima yang lst[start:end]berisi startitem -th. Saya bahkan dapat mengatakan bahwa itu adalah 'asumsi alami'.

Tetapi kadang-kadang keraguan merayap masuk dan otak saya meminta jaminan bahwa itu tidak mengandung endunsur ke-5.

Pada saat-saat ini saya mengandalkan teorema sederhana ini:

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

Properti cantik ini memberitahu saya bahwa lst[start:end]tidak mengandung enditem -th karena ada di lst[end:].

Perhatikan bahwa teorema ini berlaku untuk nsemua. Misalnya, Anda dapat memeriksanya

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

kembali True.

Robert
sumber
12

Menurut pendapat saya, Anda akan memahami dan menghafal notasi string Python yang lebih baik jika Anda melihatnya dengan cara berikut (baca terus).

Mari kita bekerja dengan string berikut ...

azString = "abcdefghijklmnopqrstuvwxyz"

Bagi mereka yang tidak tahu, Anda dapat membuat substring dari azStringmenggunakan notasiazString[x:y]

Berasal dari bahasa pemrograman lain, saat itulah akal sehat dikompromikan. Apa itu x dan y?

Saya harus duduk dan menjalankan beberapa skenario dalam pencarian saya untuk teknik menghafal yang akan membantu saya mengingat apa x dan y dan membantu saya mengiris string dengan benar pada upaya pertama.

Kesimpulan saya adalah bahwa x dan y harus dilihat sebagai indeks batas yang mengelilingi string yang ingin kita ekstra. Jadi kita harus melihat ekspresi itu azString[index1, index2]atau bahkan lebih jelasazString[index_of_first_character, index_after_the_last_character] .

Berikut adalah contoh visualisasi dari ...

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

Jadi yang harus Anda lakukan adalah mengatur index1 dan index2 ke nilai-nilai yang akan mengelilingi substring yang diinginkan. Misalnya, untuk mendapatkan substring "cdefgh", Anda dapat menggunakanazString[2:8] , karena indeks di sisi kiri "c" adalah 2 dan yang pada ukuran kanan "h" adalah 8.

Ingatlah bahwa kami sedang menetapkan batasan. Dan batas-batas itu adalah posisi di mana Anda dapat menempatkan beberapa tanda kurung yang akan dililitkan di sekitar bidang seperti ini ...

ab [ cdefgh ] ij

Trik itu bekerja sepanjang waktu dan mudah diingat.

asiby
sumber
11

Sebagian besar jawaban sebelumnya membersihkan pertanyaan tentang notasi slice.

Sintaks pengindeksan diperpanjang yang digunakan untuk mengiris adalah aList[start:stop:step], dan contoh dasar adalah:

Masukkan deskripsi gambar di sini:

Contoh yang lebih mengiris: 15 Irisan Diperpanjang

Roshan Bagdiya
sumber
10

Dalam Python, bentuk paling dasar untuk mengiris adalah sebagai berikut:

l[start:end]

di mana lbeberapa koleksi, startmerupakan indeks inklusif, dan endmerupakan indeks eksklusif.

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]

Ketika mengiris dari awal, Anda bisa menghilangkan indeks nol, dan ketika mengiris hingga akhir, Anda bisa menghilangkan indeks akhir karena itu berlebihan, jadi jangan bertele-tele:

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

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

Bilangan bulat negatif berguna ketika melakukan offset relatif terhadap akhir koleksi:

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 three elements
Out[8]: [7, 8, 9]

Adalah mungkin untuk memberikan indeks yang di luar batas ketika mengiris seperti:

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

Ingatlah bahwa hasil mengiris koleksi adalah koleksi yang sama sekali baru. Selain itu, saat menggunakan notasi irisan dalam tugas, panjang tugas irisan tidak harus sama. Nilai sebelum dan sesudah irisan yang ditugaskan akan disimpan, dan koleksi akan menyusut atau tumbuh untuk mengandung nilai-nilai baru:

In [16]: l[2:6] = list('abc') # Assigning fewer 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]

Jika Anda menghilangkan indeks awal dan akhir, Anda akan membuat salinan koleksi:

In [14]: l_copy = l[:]

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

Jika indeks awal dan akhir dihilangkan saat melakukan operasi penugasan, seluruh konten koleksi akan diganti dengan salinan apa yang dirujuk:

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

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

Selain mengiris dasar, juga dimungkinkan untuk menerapkan notasi berikut:

l[start:end:step]

di mana lkoleksi, startadalah indeks inklusif, endadalah indeks eksklusif, dan stepmerupakan langkah yang dapat digunakan untuk mengambil setiap item ke dalam l.

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]

Menggunakan stepmenyediakan trik yang berguna untuk membalikkan koleksi dengan Python:

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

Dimungkinkan juga untuk menggunakan bilangan bulat negatif stepsebagai contoh berikut:

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

Namun, menggunakan nilai negatif untuk stepbisa menjadi sangat membingungkan. Selain itu, agar Pythonic , Anda harus menghindari menggunakan start, enddan stepdalam satu irisan. Dalam hal ini diperlukan, pertimbangkan melakukan ini dalam dua tugas (satu untuk mengiris, dan yang lainnya untuk melangkah).

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]
lmiguelvargasf
sumber
10

Saya ingin menambahkan satu Hello, World! contoh yang menjelaskan dasar-dasar irisan untuk pemula. Itu banyak membantu saya.

Mari kita daftar dengan enam nilai ['P', 'Y', 'T', 'H', 'O', 'N']:

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

Sekarang irisan paling sederhana dari daftar itu adalah sublists-nya. Notasi adalah [<index>:<index>]dan kuncinya adalah membacanya seperti ini:

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

Sekarang jika Anda membuat sepotong [2:5]daftar di atas, ini akan terjadi:

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

Anda membuat potongan sebelum elemen dengan indeks 2dan potongan lain sebelum elemen dengan indeks 5. Jadi hasilnya akan menjadi irisan antara dua potongan, daftar ['T', 'H', 'O'].

Jeyekomon
sumber
10

Saya pribadi memikirkannya seperti forlingkaran:

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

Juga, perhatikan bahwa nilai negatif untuk startdan endrelatif terhadap akhir daftar dan dihitung dalam contoh di atas oleh given_index + a.shape[0].

Raman
sumber
8

Di bawah ini adalah contoh indeks string:

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

str="Name string"

Contoh irisan: [mulai: akhir: langkah]

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

Di bawah ini adalah contoh penggunaannya:

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
Pangeran Dhadwal
sumber
5

Jika Anda merasa indeks negatif dalam mengiris membingungkan, berikut adalah cara yang sangat mudah untuk memikirkannya: cukup ganti dengan indeks negatif len - index. Jadi misalnya, ganti -3 dengan len(list) - 3.

Cara terbaik untuk menggambarkan apa yang dilakukan slicing secara internal adalah hanya menunjukkannya dalam kode yang mengimplementasikan operasi ini:

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 a for-loop with start, end and step
  return [list[i] for i in range(start, end, step)]
Shital Shah
sumber
4

Teknik mengiris dasar adalah untuk menentukan titik awal, titik berhenti, dan ukuran langkah - juga dikenal sebagai langkah.

Pertama, kita akan membuat daftar nilai untuk digunakan dalam slicing kita.

Buat dua daftar untuk diiris. Yang pertama adalah daftar angka dari 1 hingga 9 (Daftar A). Yang kedua juga merupakan daftar angka, dari 0 hingga 9 (Daftar B):

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

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

Indeks angka 3 dari A dan angka 6 dari B.

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

Irisan dasar

Sintaks pengindeksan diperpanjang yang digunakan untuk mengiris adalah aList [start: stop: step]. Argumen mulai dan argumen langkah default ke tidak ada - satu-satunya argumen yang diperlukan adalah berhenti. Apakah Anda memperhatikan bahwa ini mirip dengan bagaimana rentang digunakan untuk menentukan daftar A dan B? Ini karena objek irisan mewakili set indeks yang ditentukan oleh rentang (mulai, berhenti, langkah). Dokumentasi Python 3.4.

Seperti yang Anda lihat, mendefinisikan hanya berhenti mengembalikan satu elemen. Sejak awal tidak ada, ini berarti hanya mengambil satu elemen saja.

Penting untuk dicatat, elemen pertama adalah indeks 0, bukan indeks 1. Inilah sebabnya kami menggunakan 2 daftar untuk latihan ini. Elemen Daftar A diberi nomor sesuai dengan posisi ordinal (elemen pertama adalah 1, elemen kedua adalah 2, dll.) Sedangkan elemen Daftar B adalah angka yang akan digunakan untuk mengindeksnya ([0] untuk elemen pertama 0, dll.)

Dengan sintaks pengindeksan yang diperluas, kami mengambil rentang nilai. Misalnya, semua nilai diambil dengan titik dua.

A[:]

Untuk mengambil subset elemen, posisi awal dan berhenti harus ditentukan.

Dengan pola aList [start: stop], ambil dua elemen pertama dari Daftar A.

Babu Chandermani
sumber
3

Saya tidak berpikir bahwa diagram tutorial Python (dikutip dalam berbagai jawaban lain) baik karena saran ini berfungsi untuk langkah positif, tetapi tidak untuk langkah negatif.

Ini adalah diagram:

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

Dari diagram, saya berharap a[-4,-6,-1]untuk menjadi yPtetapi ty.

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

Yang selalu berhasil adalah berpikir dalam karakter atau slot dan menggunakan pengindeksan sebagai interval setengah terbuka - kanan-terbuka jika langkah positif, kiri-terbuka jika langkah negatif.

Dengan cara ini, saya bisa menganggapnya a[-4:-6:-1]sebagai a(-6,-4]terminologi interval.

 +---+---+---+---+---+---+
 | 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  
aguadopd
sumber