Odpowiedzi:
To naprawdę bardzo proste:
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
Istnieje również step
wartość, której można użyć z dowolnym z powyższych:
a[start:stop:step] # start through not past stop, by step
Kluczową kwestią do zapamiętania jest to, że :stop
wartość reprezentuje pierwszą wartość, która nie znajduje się w wybranym wycinku. Różnica między stop
i start
to liczba wybranych elementów (jeśli step
domyślnie jest to 1).
Drugą cechą jest to, że start
albo stop
może być ujemna liczba, co oznacza, że liczy się od końca tablicy zamiast początku. Więc:
a[-1] # last item in the array
a[-2:] # last two items in the array
a[:-2] # everything except the last two items
Podobnie step
może być liczbą ujemną:
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 jest miły dla programisty, jeśli jest mniej elementów niż prosisz. Na przykład, jeśli poprosisz o a[:-2]
i a
zawiera tylko jeden element, zamiast błędu pojawi się pusta lista. Czasami wolisz błąd, więc musisz mieć świadomość, że może się to zdarzyć.
slice()
przedmiotemOperator krojenia []
jest faktycznie używany w powyższym kodzie z slice()
obiektem używającym :
notacji (która jest poprawna tylko w obrębie []
), tj .:
a[start:stop:step]
jest równa:
a[slice(start, stop, step)]
Obiekty plasterków również zachowują się nieco inaczej w zależności od liczby argumentów, podobnie jak range()
, tj. Oba slice(stop)
i slice(start, stop[, step])
są obsługiwane. Aby pominąć określenie danego argumentu, można użyć None
, aby np. Był a[start:]
równoważny a[slice(start, None)]
lub a[::-1]
równoważny a[slice(None, None, -1)]
.
Podczas gdy :
notacja na podstawie jest bardzo pomocna przy prostym krojeniu, jawne użycie slice()
obiektów upraszcza programowe generowanie krojenia.
None
dowolną pustą przestrzeń. Na przykład [None:None]
wykonuje całą kopię. Jest to przydatne, gdy musisz określić koniec zakresu za pomocą zmiennej i musisz dołączyć ostatni element.
del
notację wycinania wrt. W szczególności del arr[:]
nie jest od razu oczywiste („arr [:] tworzy kopię, więc del usuwa tę kopię ???” itd.)
W Python Tutorial mówi o nim (w dół trochę, aż dojdziesz do części o krojenie).
Schemat artystyczny ASCII jest również pomocny do zapamiętania, jak działają plastry:
+---+---+---+---+---+---+
| P | y | t | h | o | n |
+---+---+---+---+---+---+
0 1 2 3 4 5 6
-6 -5 -4 -3 -2 -1
Jednym ze sposobów na zapamiętanie działania wycinków jest myślenie o wskaźnikach wskazujących między znakami, z lewą krawędzią pierwszego znaku ponumerowaną 0. Następnie prawa krawędź ostatniego znaku ciągu n znaków ma indeks n .
a[-4,-6,-1]
tak będzie, yP
ale tak jest ty
. To, co zawsze działa, to myślenie w postaciach lub slotach i stosowanie indeksowania jako półotwartego przedziału - otwarcie prawe, jeśli krok dodatni, otwarcie lewe, jeśli krok ujemny.
x[:0]
przypadku rozpoczynania od początku), więc musisz specjalne małe tablice. : /
Wymieniając możliwości dozwolone przez gramatykę:
>>> 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]]
Oczywiście, jeśli (high-low)%stride != 0
, to punkt końcowy będzie nieco niższy niż high-1
.
Jeśli stride
jest ujemne, kolejność jest nieco zmieniona, ponieważ odliczamy:
>>> 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]]
Rozszerzone segmentowanie (z przecinkami i elipsami) jest najczęściej używane tylko przez specjalne struktury danych (takie jak NumPy); podstawowe sekwencje ich nie obsługują.
>>> class slicee:
... def __getitem__(self, item):
... return repr(item)
...
>>> slicee()[0, 1:2, ::5, ...]
'(0, slice(1, 2, None), slice(None, None, 5), Ellipsis)'
repr
__getitem__
jest; twój przykład jest równoważny z apple[slice(4, -4, -1)]
.
Odpowiedzi powyżej nie omawiają przypisania plasterków. Aby zrozumieć przypisanie plasterka, pomocne jest dodanie innej koncepcji do grafiki 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']
Jedna heurystyka polega na tym, że dla wycinka od zera do n pomyśl: „zero to początek, zacznij od początku i weź n elementów z listy”.
>>> 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']
Inna heurystyka to „w przypadku dowolnego wycinka zastąp początkową wartość zerową, zastosuj poprzednią heurystykę, aby uzyskać koniec listy, a następnie policz pierwszą liczbę z powrotem, aby odciąć elementy od początku”
>>> 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.
Pierwsza zasada przypisywania wycinka polega na tym, że ponieważ wycinanie zwraca listę, przypisanie wycinka wymaga listy (lub innej iterowalnej):
>>> 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
Drugą zasadą przypisywania wycinka, którą można również zobaczyć powyżej, jest to, że cokolwiek część listy jest zwracana przez indeksowanie wycinków, to ta sama część, która jest zmieniana przez przypisanie wycinków:
>>> p[2:4]
['T','h']
>>> p[2:4] = ['t','r']
>>> p
['P','y','t','r','o','n']
Trzecią zasadą przypisywania wycinka jest to, że przypisana lista (iterowalna) nie musi mieć tej samej długości; indeksowany plasterek jest po prostu wycinany i zastępowany masowo przez to, co jest przypisane:
>>> 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']
Najtrudniejszą częścią, do której należy się przyzwyczaić, jest przydzielanie pustych plasterków. Za pomocą heurystyki 1 i 2 łatwo jest zaindeksować indeksowanie pustego wycinka:
>>> 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]
[]
A kiedy już to zobaczysz, przypisanie wycinka do pustego wycinka również ma sens:
>>> 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
Zauważ, że ponieważ nie zmieniamy drugiej liczby wycinka (4), wstawiane elementy zawsze układają się w stos względem „o”, nawet gdy przypisujemy do pustego wycinka. Zatem pozycja dla przypisania pustego wycinka jest logicznym rozszerzeniem pozycji dla niepustych przypisań wycinka.
Cofając się trochę, co się stanie, gdy będziesz kontynuował naszą procesję liczenia początku plastra?
>>> 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]
[]
Z krojeniem, kiedy skończysz, skończysz; nie zaczyna kroić wstecz. W Pythonie nie otrzymujesz ujemnych kroków, chyba że wyraźnie poprosisz o nie, używając liczby ujemnej.
>>> p[5:3:-1]
['n','o']
Istnieją dziwne konsekwencje dla zasady „kiedy skończysz, skończysz”:
>>> 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
W rzeczywistości, w porównaniu do indeksowania, krojenie w Pythonie jest dziwnie odporne na błędy:
>>> p[100:200]
[]
>>> p[int(2e99):int(1e99)]
[]
Czasami może się to przydać, ale może również prowadzić do nieco dziwnych zachowań:
>>> 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']
W zależności od aplikacji może to ... lub nie ... być tym, na co liczyłeś!
Poniżej znajduje się tekst mojej oryginalnej odpowiedzi. Przydał się wielu osobom, więc nie chciałem go usuwać.
>>> 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]
Może to również wyjaśnić różnicę między krojeniem a indeksowaniem.
Wyjaśnij notację plastra Pythona
W skrócie, dwukropek ( :
) w notacji indeksem ( subscriptable[subscriptarg]
) make plaster notacja - który ma opcjonalnych argumentów start
, stop
, step
:
sliceable[start:stop:step]
Wycinanie w języku Python jest obliczeniowo szybkim sposobem na metodyczny dostęp do części danych. Moim zdaniem, aby być nawet pośrednim programistą Python, jest to jeden z aspektów języka, który trzeba znać.
Na początek zdefiniujmy kilka terminów:
start: indeks początkowy wycinka, będzie zawierał element o tym indeksie, chyba że jest taki sam jak stop , domyślnie 0, tzn. pierwszy indeks. Jeśli jest ujemny, oznacza to, że zaczynasz
n
przedmioty od końca.stop: indeks końcowy wycinka, nie zawiera elementu o tym indeksie, domyślnie długość odcinki jest wycinana, to znaczy do końca włącznie.
krok: kwota, o którą indeks rośnie, domyślnie wynosi 1. Jeśli jest ujemny, przecinasz iterację w odwrotnej kolejności.
Możesz wykonać dowolną z tych liczb dodatnich lub ujemnych. Znaczenie liczb dodatnich jest prosta, ale dla liczb ujemnych, podobnie jak indeksy w Pythonie, można liczyć wstecz od końca do początku i zatrzymania , a po kroku , po prostu zmniejszyć swój indeks. Ten przykład pochodzi z samouczka dokumentacji , ale nieco go zmodyfikowałem, aby wskazać, który element w sekwencji odnosi się do każdego indeksu:
+---+---+---+---+---+---+
| P | y | t | h | o | n |
+---+---+---+---+---+---+
0 1 2 3 4 5
-6 -5 -4 -3 -2 -1
Aby użyć notacji wycinka z sekwencją, która ją obsługuje, musisz umieścić co najmniej jeden dwukropek w nawiasach kwadratowych następujących po sekwencji (które faktycznie implementują __getitem__
metodę sekwencji, zgodnie z modelem danych Python ).
Notacja wycinka działa w następujący sposób:
sequence[start:stop:step]
I pamiętaj, że istnieją wartości domyślne dla startu , stopu i kroku , więc aby uzyskać dostęp do wartości domyślnych, po prostu pomiń argument.
Notacja plastra, aby uzyskać ostatnie dziewięć elementów z listy (lub dowolnej innej sekwencji, która ją obsługuje, np. Ciąg znaków) wyglądałaby następująco:
my_list[-9:]
Kiedy to widzę, czytam tę część w nawiasach jako „9. od końca do końca”. (Właściwie to nazywam to mentalnie jako „-9, on”)
Pełna notacja to
my_list[-9:None:None]
i aby zastąpić wartości domyślne (w rzeczywistości, gdy wartość step
jest ujemna, stop
wartość domyślna to -len(my_list) - 1
, więc None
dla stop naprawdę oznacza to, że przechodzi do dowolnego kroku końcowego, do którego prowadzi):
my_list[-9:len(my_list):1]
Okrężnicy , :
jest to, co mówi Python dajesz mu kawałek, a nie regularne indeksu. Właśnie dlatego idiomatycznym sposobem tworzenia płytkiej kopii list w Pythonie 2 jest
list_copy = sequence[:]
I ich usunięcie polega na:
del my_list[:]
(Python 3 otrzymuje metodę list.copy
a list.clear
).
step
jest ujemne, wartości domyślne start
i stop
zmieniają sięDomyślnie, gdy step
argument jest pusty (lub None
), zostaje przypisany do +1
.
Ale możesz podać ujemną liczbę całkowitą, a lista (lub większość innych standardowych slicabli) zostanie pocięta od końca do początku.
Tak więc negatywny plasterek zmieni wartości domyślne dla start
i stop
!
Chciałbym zachęcić użytkowników do zapoznania się ze źródłem oraz dokumentacją. Kod źródłowy wycinka obiektów i ta logika jest znaleźć tutaj . Najpierw określamy, czy step
jest ujemny:
step_is_negative = step_sign < 0;
Jeśli tak, dolna granica -1
oznacza, że przecinamy aż do początku włącznie, a górna granica to długość minus 1, co oznacza, że zaczynamy od końca. (Należy pamiętać, że semantyka ta -1
jest różna od A -1
czemu użytkownicy mogą przechodzić indeksów w Pythonie wskazujące ostatni element).
if (step_is_negative) { lower = PyLong_FromLong(-1L); if (lower == NULL) goto error; upper = PyNumber_Add(length, lower); if (upper == NULL) goto error; }
W przeciwnym razie step
jest dodatnia, a dolna granica będzie wynosić zero, a górna granica (do której idziemy do góry, ale nie obejmuje) długości podzielonej listy.
else { lower = _PyLong_Zero; Py_INCREF(lower); upper = length; Py_INCREF(upper); }
Następnie może być konieczne zastosowanie wartości domyślnych dla start
i stop
- wartość domyślna wtedy dla start
jest obliczana jako górna granica, gdy step
jest ujemna:
if (self->start == Py_None) { start = step_is_negative ? upper : lower; Py_INCREF(start); }
i stop
dolna granica:
if (self->stop == Py_None) { stop = step_is_negative ? lower : upper; Py_INCREF(stop); }
Przydatne może być oddzielenie formowania wycinka od przekazania go do list.__getitem__
metody ( to właśnie robią nawiasy kwadratowe ). Nawet jeśli nie jesteś nowy, kod jest bardziej czytelny, dzięki czemu inni, którzy mogą przeczytać kod, mogą łatwiej zrozumieć, co robisz.
Nie można jednak przypisać zmiennej do liczb całkowitych oddzielonych dwukropkami. Musisz użyć obiektu plasterka:
last_nine_slice = slice(-9, None)
Drugi argument, None
jest wymagany, aby pierwszy argument był interpretowany jako start
argument, w przeciwnym razie byłby to stop
argument .
Następnie możesz przekazać obiekt plasterka do swojej sekwencji:
>>> list(range(100))[last_nine_slice]
[91, 92, 93, 94, 95, 96, 97, 98, 99]
Interesujące jest to, że zakresy również biorą plasterki:
>>> range(100)[last_nine_slice]
range(91, 100)
Ponieważ wycinki list w języku Python tworzą nowe obiekty w pamięci, kolejną ważną funkcją, o której należy pamiętać, jest itertools.islice
. Zazwyczaj będziesz chciał iterować fragment, a nie tylko utworzyć go statycznie w pamięci. islice
jest do tego idealny. Zastrzeżenie, nie obsługuje negatywnych argumentów na rzecz start
, stop
lub step
, jeśli jest to problem, może być konieczne obliczenie indeksów lub odwrócenie iterowalności z góry.
length = 100
last_nine_iter = itertools.islice(list(range(length)), length-9, None, 1)
list_last_nine = list(last_nine_iter)
i teraz:
>>> list_last_nine
[91, 92, 93, 94, 95, 96, 97, 98, 99]
Fakt, że wycinki list tworzą kopię, jest cechą samych list. Jeśli kroisz zaawansowane obiekty, takie jak Pandas DataFrame, może zwrócić widok oryginału, a nie jego kopię.
I kilka rzeczy, które nie były od razu dla mnie oczywiste, kiedy po raz pierwszy zobaczyłem składnię krojenia:
>>> x = [1,2,3,4,5,6]
>>> x[::-1]
[6,5,4,3,2,1]
Łatwy sposób na odwrócenie sekwencji!
A jeśli z jakiegoś powodu chciałeś, co drugi element w odwrotnej kolejności:
>>> x = [1,2,3,4,5,6]
>>> x[::-2]
[6,4,2]
W Pythonie 2.7
Krojenie w Pythonie
[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).
Zrozumienie przypisania indeksu jest bardzo ważne.
In forward direction, starts at 0 and ends at len-1
In backward direction, starts at -1 and ends at -len
Kiedy mówisz [a: b: c], mówisz w zależności od znaku c (do przodu lub do tyłu), zacznij od a, a zakończ na b (wyłączając element przy bth index). Użyj powyższej reguły indeksowania i pamiętaj, że znajdziesz tylko elementy z tego zakresu:
-len, -len+1, -len+2, ..., 0, 1, 2,3,4 , len -1
Ale zasięg ten jest kontynuowany w obu kierunkach w nieskończoność:
...,-len -2 ,-len-1,-len, -len+1, -len+2, ..., 0, 1, 2,3,4 , len -1, len, len +1, len+2 , ....
Na przykład:
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
Jeśli twój wybór a, b i c pozwala na pokrywanie się z powyższym zakresem podczas przechodzenia za pomocą reguł dla a, b, c powyżej, albo otrzymasz listę z elementami (dotkniętymi podczas przechodzenia), albo dostaniesz pustą listę.
I ostatnia rzecz: jeśli aib są równe, to również otrzymujesz pustą listę:
>>> 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]
a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]; a[:-2:-2]
który prowadzi do[9]
Znalazłem ten wielki stół na 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)
Po odrobinie użycia zdaję sobie sprawę, że najprostszym opisem jest to, że jest dokładnie taki sam jak argumenty w for
pętli ...
(from:to:step)
Każda z nich jest opcjonalna:
(:to:step)
(from::step)
(from:to)
Następnie indeksowanie ujemne wymaga tylko dodania długości łańcucha do indeksów ujemnych, aby go zrozumieć.
W każdym razie to działa dla mnie ...
Łatwiej jest mi zapamiętać, jak to działa, a potem mogę wymyślić dowolną kombinację start / stop / krok.
Warto range()
najpierw zrozumieć :
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
Zacznij od start
, zwiększaj step
, nie sięgaj stop
. Bardzo prosta.
O kroku ujemnym należy pamiętać, że stop
zawsze jest to koniec wykluczony, niezależnie od tego, czy jest wyższy czy niższy. Jeśli chcesz tego samego plasterka w odwrotnej kolejności, znacznie łatwiej jest wykonać odwrócenie osobno: np. 'abcde'[1:-2][::-1]
Odciąć jeden znak od lewej, dwa od prawej, a następnie cofa. (Zobacz także reversed()
.)
Krojenie sekwencji jest takie samo, z tym wyjątkiem, że najpierw normalizuje indeksy ujemne i nigdy nie może wyjść poza sekwencję:
DO ZROBIENIA : Poniższy kod zawiera błąd „nigdy nie wychodź poza sekwencję”, gdy abs (krok)> 1; Myślę , że załatałem to, żeby było poprawne, ale trudno to zrozumieć.
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]
Nie martw się o is None
szczegóły - pamiętaj tylko, że pominięcie start
i / lub stop
zawsze robi to dobrze, aby dać ci całą sekwencję.
Normalizacja ujemnych indeksów najpierw pozwala na liczenie startu i / lub zatrzymania od końca niezależnie: 'abcde'[1:-2] == 'abcde'[1:3] == 'bc'
pomimo range(1,-2) == []
. Normalizacja jest czasem uważana za „modulo długość”, ale należy pamiętać, że dodaje długość tylko raz: np. 'abcde'[-53:42]
Jest to cały ciąg.
this_is_how_slicing_works
nie to samo co plasterek Pythona. EG [0, 1, 2][-5:3:3]
otrzyma [0] w pythonie, ale list(this_is_how_slicing_works([0, 1, 2], -5, 3, 3))
dostanie [1].
range(4)[-200:200:3] == [0, 3]
ale list(this_is_how_slicing_works([0, 1, 2, 3], -200, 200, 3)) == [2]
. Moja if 0 <= i < len(seq):
próba wdrożenia po prostu „nigdy nie wychodź poza sekwencję”, ale jest błędna dla kroku> 1. Przepiszę go później dzisiaj (z testami).
Sam o tym myślę, używając metody „indeksu punktów między elementami”, ale jednym ze sposobów jej opisania, który czasem pomaga innym, jest:
mylist[X:Y]
X jest indeksem pierwszego pożądanego elementu.
Y jest indeksem pierwszego elementu, którego nie chcesz.
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 :
|--------------->
<---------------|
Mam nadzieję, że pomoże to w modelowaniu listy w Pythonie.
Odniesienie: http://wiki.python.org/moin/MovingToPythonFromOtherLanguages
Notacja krojenia w języku Python:
a[start:end:step]
start
i end
ujemne wartości są interpretowane jako odnoszące się do końca sekwencji.end
wskazują pozycję po ostatnim uwzględnionym elemencie.[+0:-0:1]
.start
iend
Notacja rozciąga się na (liczbowe) macierze i tablice wielowymiarowe. Na przykład, aby pokroić całe kolumny, możesz użyć:
m[::,0:2:] ## slice the first two columns
Plasterki zawierają odniesienia, a nie kopie elementów tablicy. Jeśli chcesz zrobić oddzielną kopię tablicy, możesz użyć deepcopy()
.
To tylko dodatkowe informacje ... Rozważ poniższą listę
>>> l=[12,23,345,456,67,7,945,467]
Kilka innych sztuczek do odwracania listy:
>>> 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]
Oto jak uczę początkujących plasterków:
Zrozumienie różnicy między indeksowaniem a krojeniem:
Wiki Python ma ten niesamowity obraz, który wyraźnie odróżnia indeksowanie i krojenie.
Jest to lista z sześcioma elementami. Aby lepiej zrozumieć krojenie, rozważ tę listę jako zestaw sześciu pudełek razem. Każde pudełko ma alfabet.
Indeksowanie przypomina postępowanie z zawartością ramki. Możesz sprawdzić zawartość dowolnego pola. Ale nie można sprawdzić zawartości wielu pól jednocześnie. Możesz nawet wymienić zawartość pudełka. Ale nie możesz umieścić dwóch piłek w jednym pudełku ani zastąpić dwóch piłek jednocześnie.
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
Krojenie jest jak radzenie sobie z pudełkami. Możesz podnieść pierwsze pudełko i umieścić je na innym stole. Aby podnieść skrzynkę, wszystko, co musisz wiedzieć, to pozycja początku i końca skrzynki.
Możesz nawet odebrać pierwsze trzy pola lub ostatnie dwa pola lub wszystkie pola od 1 do 4. Możesz więc wybrać dowolny zestaw pól, jeśli znasz początek i koniec. Pozycje te nazywane są pozycjami start i stop.
Interesujące jest to, że możesz zastąpić wiele pól jednocześnie. Możesz także umieścić wiele pól w dowolnym miejscu.
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']
Krojenie za pomocą kroku:
Do tej pory ciągle wybierałeś pudełka. Ale czasami musisz odebrać dyskretnie. Na przykład możesz odebrać co drugie pudełko. Możesz nawet odebrać co trzecie pudełko od końca. Ta wartość nazywa się wielkością kroku. To reprezentuje lukę między kolejnymi przetwornikami. Rozmiar kroku powinien być dodatni, jeśli wybierasz pudełka od początku do końca i odwrotnie.
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]: []
Jak Python rozpoznaje brakujące parametry:
Podczas krojenia, jeśli pominiesz jakiś parametr, Python spróbuje go rozgryźć automatycznie.
Jeśli sprawdzisz kod źródłowy CPython , znajdziesz funkcję o nazwie PySlice_GetIndicesEx (), która oblicza wskaźniki dla wycinka dla dowolnych podanych parametrów. Oto logiczny równoważny kod w Pythonie.
Ta funkcja pobiera obiekt Python i opcjonalne parametry do krojenia i zwraca długość początku, zatrzymania, kroku i długości żądanego plasterka.
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)
To inteligencja obecna za plasterkami. Ponieważ Python ma wbudowaną funkcję o nazwie plasterek, możesz przekazać niektóre parametry i sprawdzić, jak mądrze oblicza brakujące parametry.
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]
Uwaga: ten post został pierwotnie napisany na moim blogu, The Intelligence Behind Python Slices .
Zasadą jest, że pisanie kodu z wieloma zakodowanymi wartościami indeksu prowadzi do bałaganu w zakresie czytelności i konserwacji. Na przykład, jeśli wrócisz do kodu rok później, popatrzysz na niego i zastanawiasz się, co myślisz, kiedy go napisałeś. Przedstawione rozwiązanie jest po prostu sposobem na wyraźniejsze określenie, co faktycznie robi Twój kod. Ogólnie rzecz biorąc, wbudowany slice () tworzy obiekt plasterka, którego można używać wszędzie tam, gdzie dozwolony jest kawałek. Na przykład:
>>> 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]
Jeśli masz instancję wycinka, możesz uzyskać więcej informacji na ten temat, patrząc odpowiednio na jego atrybuty s.start, s.stop i s.step. Na przykład:
>>> a = slice(10, 50, 2) >>> a.start 10 >>> a.stop 50 >>> a.step 2 >>>
Upraszczając, pamiętaj, że plasterek ma tylko jedną formę form
s[start:end:step]
a oto jak to działa:
s
: obiekt, który można pokroićstart
: pierwszy indeks, aby rozpocząć iteracjęend
: ostatni indeks, UWAGA, że end
indeks nie zostanie uwzględniony w wynikowym wycinkustep
: wybierz element w każdym step
indeksieKolejny import rzecz: wszyscy start
, end
, step
można pominąć! A jeśli są one pomijane, ich wartość zostanie użyta domyślna: 0
, len(s)
, 1
odpowiednio.
Możliwe warianty to:
# 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[:]
UWAGA: Jeśli start >= end
(rozważając tylko kiedy step>0
), Python zwróci pusty plasterek []
.
W powyższej części wyjaśniono podstawowe funkcje działania wycinka i zadziała ono w większości przypadków. Mogą jednak wystąpić pułapki, na które należy uważać, a ta część wyjaśnia je.
Pierwszą rzeczą, która dezorientuje uczących się języka Python, jest to, że indeks może być ujemny! Nie panikuj: ujemny indeks oznacza liczyć wstecz.
Na przykład:
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].
Sprawianie, że rzeczy są bardziej mylące, step
może być również negatywne!
Krok ujemny oznacza iterację tablicy do tyłu: od końca do początku, z włączonym indeksem końcowym i indeksem początkowym wykluczonym z wyniku.
UWAGA : gdy krok jest ujemny, domyślną wartością start
jest len(s)
(chociaż end
nie jest równy 0
, ponieważ s[::-1]
zawiera s[0]
). Na przykład:
s[::-1] # Reversed slice
s[len(s)::-1] # The same as above, reversed slice
s[0:len(s):-1] # Empty list
Zaskocz się: wycinek nie podnosi błędu indeksu, gdy indeks jest poza zakresem!
Jeśli indeks jest poza zakresem, Python dołoży wszelkich starań, aby ustawić indeks na 0
lub len(s)
zgodnie z sytuacją. Na przykład:
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]
Zakończmy tę odpowiedź przykładami, wyjaśniając wszystko, co omówiliśmy:
# 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
Poprzednie odpowiedzi nie omawiają wielowymiarowego dzielenia tablic, co jest możliwe przy użyciu słynnego pakietu NumPy :
Krojenie można również zastosować do tablic wielowymiarowych.
# 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
” Przed przecinkiem operuje na pierwszym wymiarze, a „ 0:3:2
” po przecinku na drugim wymiarze.
list
ale tylko array
w Numpy
#!/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)
Możesz uruchomić ten skrypt i eksperymentować z nim, poniżej jest kilka próbek, które otrzymałem ze skryptu.
+---+---+---+---+---+---+---+---+---+
| 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]
W przypadku kroku ujemnego zwróć uwagę, że odpowiedź jest przesunięta w prawo o 1.
Mój mózg wydaje się szczęśliwy, że lst[start:end]
zawiera start
-ty element. Mógłbym nawet powiedzieć, że jest to „naturalne założenie”.
Ale czasami pojawiają się wątpliwości i mój mózg prosi o zapewnienie, że nie zawiera on-tego end
elementu.
W tych momentach opieram się na tym prostym twierdzeniu:
for any n, lst = lst[:n] + lst[n:]
Ta ładna właściwość mówi mi, że lst[start:end]
nie zawiera end
-tego elementu, ponieważ jest w lst[end:]
.
Zauważ, że to twierdzenie jest prawdziwe dla każdego n
. Na przykład możesz to sprawdzić
lst = range(10)
lst[:-42] + lst[-42:] == lst
zwraca True
.
Moim zdaniem lepiej zrozumiesz i zapamiętasz notację krojenia ciągów znaków w Pythonie, jeśli spojrzysz na nią w następujący sposób (czytaj dalej).
Pracujmy z następującym ciągiem ...
azString = "abcdefghijklmnopqrstuvwxyz"
Dla tych, którzy nie wiedzą, możesz utworzyć dowolny podciąg azString
za pomocą notacjiazString[x:y]
Pochodząc z innych języków programowania, wtedy zdrowy rozsądek zostaje naruszony. Co to są xiy?
Musiałem usiąść i uruchomić kilka scenariuszy, szukając techniki zapamiętywania, która pomoże mi zapamiętać, czym są xiy, i pomoże mi prawidłowo przeciąć łańcuchy przy pierwszej próbie.
Mój wniosek jest taki, że xiy należy postrzegać jako indeksy brzegowe otaczające ciągi, które chcemy uzupełnić. Powinniśmy więc postrzegać to wyrażenie jako azString[index1, index2]
lub nawet bardziej wyraźne jako azString[index_of_first_character, index_after_the_last_character]
.
Oto przykładowa wizualizacja tego ...
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
Wszystko, co musisz zrobić, to ustawić indeks1 i indeks2 na wartości, które będą otaczały pożądany podciąg. Na przykład, aby uzyskać podciąg „cdefgh”, możesz użyć azString[2:8]
, ponieważ indeks po lewej stronie „c” wynosi 2, a indeks po prawej stronie „h” to 8.
Pamiętaj, że wyznaczamy granice. A tymi granicami są pozycje, w których można umieścić nawiasy klamrowe, które zostaną owinięte wokół podciągu w ten sposób ...
ab [ cdefgh ] ij
Ta sztuczka działa cały czas i łatwo ją zapamiętać.
Większość poprzednich odpowiedzi wyjaśnia pytania dotyczące notacji plastra.
Rozszerzona składnia indeksowania używana do krojenia jest aList[start:stop:step]
, a podstawowe przykłady to:
Więcej przykładów krojenia: 15 rozszerzonych krojów
W Pythonie najbardziej podstawową formą krojenia jest:
l[start:end]
gdzie l
jest jakaś kolekcja, start
jest indeksem włączającym i end
jest indeksem wyłącznym.
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]
Podczas krojenia od samego początku można pominąć indeks zerowy, a podczas krojenia do końca można pominąć indeks końcowy, ponieważ jest on zbędny, więc nie należy powtarzać:
In [5]: l[:3] == l[0:3]
Out[5]: True
In [6]: l[7:] == l[7:len(l)]
Out[6]: True
Ujemne liczby całkowite są użyteczne podczas wykonywania przesunięć względem końca kolekcji:
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]
Podczas krojenia można podać wskaźniki, które są poza zakresem, takie jak:
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]
Pamiętaj, że wynikiem krojenia kolekcji jest zupełnie nowa kolekcja. Ponadto w przypadku przypisania wycinka w przypisaniach długość przypisań wycinka nie musi być taka sama. Wartości przed i po przypisanym wycinku zostaną zachowane, a kolekcja zmniejszy się lub powiększy, aby zawierać nowe wartości:
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]
Jeśli pominiesz indeks początkowy i końcowy, utworzysz kopię kolekcji:
In [14]: l_copy = l[:]
In [15]: l == l_copy and l is not l_copy
Out[15]: True
Jeśli indeksy początkowy i końcowy zostaną pominięte podczas wykonywania operacji przypisania, cała zawartość kolekcji zostanie zastąpiona kopią tego, do którego się odwołuje:
In [20]: l[:] = list('hello...')
In [21]: l
Out[21]: ['h', 'e', 'l', 'l', 'o', '.', '.', '.']
Oprócz podstawowego krojenia można również zastosować następującą notację:
l[start:end:step]
gdzie l
jest kolekcją, start
jest indeksem włączającym, end
jest indeksem wyłącznym i step
jest krokiem, którego można użyć, aby wziąć co n-ty przedmiot 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]
Użycie step
zapewnia przydatną sztuczkę do odwrócenia kolekcji w Pythonie:
In [25]: l[::-1]
Out[25]: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
Możliwe jest również użycie ujemnych liczb całkowitych dla step
następującego przykładu:
In[28]: l[::-2]
Out[28]: [9, 7, 5, 3, 1]
Jednak użycie wartości ujemnej dla step
może stać się bardzo mylące. Ponadto, aby być pythonic , należy unikać start
, end
oraz step
w pojedynczym segmencie. Jeśli jest to wymagane, zastanów się nad zrobieniem tego w dwóch zadaniach (jednym do pokrojenia, a drugim do kroku).
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]
Chcę dodać jedno Witaj, świecie! przykład wyjaśniający podstawy plasterków dla początkujących. Bardzo mi pomogło.
Zróbmy listę z sześcioma wartościami ['P', 'Y', 'T', 'H', 'O', 'N']
:
+---+---+---+---+---+---+
| P | Y | T | H | O | N |
+---+---+---+---+---+---+
0 1 2 3 4 5
Teraz najprostszymi plasterkami tej listy są podlisty. Notacja jest, [<index>:<index>]
a kluczem jest odczytanie jej w następujący sposób:
[ start cutting before this index : end cutting before this index ]
Teraz, jeśli utworzysz kawałek [2:5]
powyższej listy, stanie się to:
| |
+---+---|---+---+---|---+
| P | Y | T | H | O | N |
+---+---|---+---+---|---+
0 1 | 2 3 4 | 5
Wykonałeś cięcie przed elementem z indeksem 2
i kolejne cięcie przed elementem z indeksem 5
. Tak więc wynikiem będzie plasterek między tymi dwoma cięciami, lista ['T', 'H', 'O']
.
Poniżej znajduje się przykład indeksu ciągu:
+---+---+---+---+---+
| H | e | l | p | A |
+---+---+---+---+---+
0 1 2 3 4 5
-5 -4 -3 -2 -1
str="Name string"
Przykład krojenia: [start: koniec: krok]
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
Poniżej znajduje się przykładowe użycie:
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
Jeśli uważasz, że ujemne wskaźniki w krojeniu są mylące, oto bardzo prosty sposób, aby o tym pomyśleć: po prostu zastąp indeks ujemny przez len - index
. Na przykład zamień -3 na len(list) - 3
.
Najlepszym sposobem zilustrowania wewnętrznego podziału na plastry jest po prostu pokazanie go w kodzie implementującym tę operację:
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)]
Podstawową techniką krojenia jest określenie punktu początkowego, punktu zatrzymania i wielkości kroku - znanej również jako krok.
Najpierw stworzymy listę wartości do wykorzystania w naszym krojeniu.
Utwórz dwie listy do wycięcia. Pierwsza to lista numeryczna od 1 do 9 (Lista A). Druga to także lista numeryczna od 0 do 9 (Lista 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)
Zindeksuj liczbę 3 od A i liczbę 6 od B.
print(A[2])
print(B[6])
Podstawowe krojenie
Rozszerzona składnia indeksowania używana do krojenia to aList [start: stop: step]. Argument początkowy i krokowy domyślnie nie ma wartości - jedynym wymaganym argumentem jest stop. Czy zauważyłeś, że jest to podobne do tego, w jaki sposób użyto zakresu do zdefiniowania list A i B? Wynika to z faktu, że obiekt wycinka reprezentuje zestaw wskaźników określonych przez zakres (początek, stop, krok). Dokumentacja Python 3.4.
Jak widać, zdefiniowanie tylko stop zwraca jeden element. Ponieważ domyślnym początkiem jest brak, przekłada się to na pobranie tylko jednego elementu.
Należy zauważyć, że pierwszym elementem jest indeks 0, a nie indeks 1. Dlatego do tego ćwiczenia używamy 2 list. Elementy listy A są ponumerowane zgodnie z pozycją porządkową (pierwszy element to 1, drugi element to 2 itd.), Natomiast elementy listy B to liczby, które zostałyby użyte do ich indeksowania ([0] dla pierwszego elementu 0, itp.).
Dzięki rozszerzonej składni indeksowania pobieramy zakres wartości. Na przykład wszystkie wartości są pobierane za pomocą dwukropka.
A[:]
Aby pobrać podzbiór elementów, należy zdefiniować pozycje początkową i końcową.
Biorąc pod uwagę wzorzec aList [start: stop], pobierz pierwsze dwa elementy z Listy A.
Nie sądzę, że schemat samouczka w języku Python (cytowany w różnych innych odpowiedziach) jest dobry, ponieważ ta sugestia działa pozytywnie, ale nie działa negatywnie.
Oto schemat:
+---+---+---+---+---+---+
| P | y | t | h | o | n |
+---+---+---+---+---+---+
0 1 2 3 4 5 6
-6 -5 -4 -3 -2 -1
Z diagramu oczekuję, że a[-4,-6,-1]
tak będzie, yP
ale tak jest ty
.
>>> a = "Python"
>>> a[2:4:1] # as expected
'th'
>>> a[-4:-6:-1] # off by 1
'ty'
To, co zawsze działa, to myślenie w postaciach lub slotach i stosowanie indeksowania jako półotwartego przedziału - otwarcie prawe, jeśli krok dodatni, otwarcie lewe, jeśli krok ujemny.
W ten sposób mogę myśleć a[-4:-6:-1]
, jak a(-6,-4]
w przedziale terminologii.
+---+---+---+---+---+---+
| 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