Comprensione della notazione delle sezioni


3285

Ho bisogno di una buona spiegazione (i riferimenti sono un vantaggio) sulla notazione di slice di Python.

Per me, questa notazione ha bisogno di essere ripresa.

Sembra estremamente potente, ma non ci ho ancora pensato.

Risposte:


4508

È piuttosto semplice davvero:

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

C'è anche il stepvalore, che può essere utilizzato con uno dei precedenti:

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

Il punto chiave da ricordare è che il :stopvalore rappresenta il primo valore che non si trova nella sezione selezionata. Quindi, la differenza tra stope startè il numero di elementi selezionati (se stepè 1, il valore predefinito).

L'altra caratteristica è che starto stoppuò essere un numero negativo , il che significa che conta dalla fine dell'array anziché dall'inizio. Così:

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

Allo stesso modo, steppuò essere un numero negativo:

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 è gentile con il programmatore se ci sono meno elementi di quelli richiesti. Ad esempio, se si richiede a[:-2]e acontiene solo un elemento, viene visualizzato un elenco vuoto anziché un errore. A volte preferisci l'errore, quindi devi essere consapevole che ciò può accadere.

Relazione con l' slice()oggetto

L'operatore slicing []viene effettivamente utilizzato nel codice sopra con un slice()oggetto usando la :notazione (che è valida solo all'interno []), ovvero:

a[start:stop:step]

è equivalente a:

a[slice(start, stop, step)]

Anche gli oggetti Slice si comportano in modo leggermente diverso a seconda del numero di argomenti, analogamente a range()entrambi, slice(stop)e slice(start, stop[, step])sono supportati. Per saltare la specifica di un determinato argomento, si potrebbe usare None, in modo che eg a[start:]sia equivalente a[slice(start, None)]o a[::-1]equivalente a[slice(None, None, -1)].

Mentre la :notazione basata su basi è molto utile per lo slicing semplice, l'uso esplicito di slice()oggetti semplifica la generazione programmatica dello slicing.


122
L'affettatura dei tipi predefiniti restituisce una copia ma non è universale. In particolare, il sezionamento delle matrici NumPy restituisce una vista che condivide la memoria con l'originale.
Beni Cherniavsky-Paskin,

43
Questa è una bella risposta con i voti per dimostrarlo, ma manca una cosa: puoi sostituire Nonequalsiasi spazio vuoto. Ad esempio [None:None]crea un'intera copia. Ciò è utile quando è necessario specificare la fine dell'intervallo utilizzando una variabile e è necessario includere l'ultimo elemento.
Mark Ransom,

6
Ciò che mi infastidisce davvero è che Python dice che quando non si imposta l'inizio e la fine, vengono impostati automaticamente su 0 e sulla lunghezza della sequenza. Quindi, in teoria, quando usi "abcdef" [:: - 1] dovrebbe essere trasformato in "abcdef" [0: 6: -1], ma queste due espressioni non ottengono lo stesso output. Sento che manca qualcosa nella documentazione di Python dalla creazione della lingua.
axell13,

6
E so che "abcdef" [:: - 1] viene trasformato in "abcdef" [6: -7: -1], quindi il modo migliore per spiegare sarebbe: lascia che len sia la lunghezza della sequenza. Se il passaggio è positivo , i valori predefiniti per inizio e fine sono 0 e len . Altrimenti se il passaggio è negativo , i valori predefiniti per l'inizio e la fine sono len e - len - 1.
axell13

4
Poiché stackoverflow.com/questions/39241529/… è contrassegnato come duplicato di questo, avrebbe senso aggiungere una sezione con ciò che delcontiene la notazione slice. In particolare, del arr[:]non è immediatamente evidente ("arr [:] crea una copia, quindi elimina quella copia ???" ecc.)
khazhyk,

538

Il tutorial di Python ne parla (scorri un po 'verso il basso fino ad arrivare alla parte sull'affettamento).

Il diagramma di arte ASCII è utile anche per ricordare come funzionano le sezioni:

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

Un modo per ricordare come funzionano le sezioni è pensare agli indici come a un punto tra i caratteri, con il bordo sinistro del primo carattere numerato 0. Quindi il bordo destro dell'ultimo carattere di una stringa di n caratteri ha l'indice n .


10
Questo suggerimento funziona per il passo positivo, ma non per un passo negativo. Dal diagramma, mi aspetto a[-4,-6,-1]di esserlo yPma lo è ty. Quello che funziona sempre è pensare nei caratteri o negli slot e usare l'indicizzazione come intervallo semiaperto: apertura a destra se falcata positiva, apertura a sinistra se falcata negativa.
aguadopd,

Ma non c'è modo di comprimere in un set vuoto a partire dalla fine (come x[:0]quando si inizia dall'inizio), quindi è necessario creare array di piccole dimensioni per casi speciali. : /
endolith il

412

Enumerando le possibilità consentite dalla grammatica:

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

Naturalmente, se (high-low)%stride != 0, il punto finale sarà leggermente inferiore a high-1.

Se strideè negativo, l'ordinamento è leggermente cambiato dal momento che stiamo contando:

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

Lo slicing esteso (con virgole e puntini di sospensione) viene utilizzato principalmente da strutture dati speciali (come NumPy); le sequenze di base non le supportano.

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

In realtà c'è ancora qualcosa che non viene visualizzato, ad esempio se digito 'apple' [4: -4: -1] Ottengo 'elp', forse Python sta traducendo il -4 in 1?
Liyuan

si noti che i backtick sono deprecati in favore direpr
wjandrea,

@liyuan Il tipo di implementazione __getitem__è; il tuo esempio è equivalente a apple[slice(4, -4, -1)].
Chepner,

320

Le risposte sopra non parlano dell'assegnazione delle sezioni. Per comprendere l'assegnazione delle sezioni, è utile aggiungere un altro concetto all'arte 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']

Una euristica è, per una sezione da zero a n, pensare: "zero è l'inizio, iniziare dall'inizio e prendere n elementi in un elenco".

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

Un altro euristico è, "per qualsiasi slice, sostituire l'inizio con zero, applicare l'euristica precedente per ottenere la fine dell'elenco, quindi contare il primo numero di backup per tagliare gli elementi all'inizio"

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

La prima regola dell'assegnazione delle sezioni è che, poiché la suddivisione restituisce un elenco, l'assegnazione delle sezioni richiede un elenco (o altro iterabile):

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

La seconda regola di assegnazione delle sezioni, che puoi anche vedere sopra, è che qualunque parte dell'elenco venga restituita dall'indicizzazione delle sezioni, questa è la stessa porzione che viene modificata dall'assegnazione delle sezioni:

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

La terza regola di assegnazione delle sezioni è che l'elenco assegnato (iterabile) non deve avere la stessa lunghezza; la sezione indicizzata viene semplicemente tagliata e sostituita in massa da qualsiasi cosa venga assegnata:

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

La parte più difficile a cui abituarsi è l'assegnazione a sezioni vuote. Usando l'euristico 1 e 2 è facile orientarsi indicizzando una fetta vuota:

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

E poi, una volta che l'hai visto, ha senso anche l'assegnazione delle sezioni alla sezione vuota:

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

Si noti che, poiché non stiamo modificando il secondo numero della sezione (4), gli elementi inseriti si impilano sempre esattamente contro la 'o', anche quando stiamo assegnando la sezione vuota. Pertanto, la posizione per l'assegnazione di sezioni vuote è l'estensione logica delle posizioni per le assegnazioni di sezioni non vuote.

Backup un po ', cosa succede quando continui con la nostra processione di contare l'inizio della fetta?

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

Con lo slicing, una volta che hai finito, hai finito; non inizia a tagliare all'indietro. In Python non ottieni passi da gigante a meno che tu non li richieda esplicitamente usando un numero negativo.

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

Ci sono alcune strane conseguenze sulla regola "una volta che hai finito, hai finito":

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

In effetti, rispetto all'indicizzazione, il slicing di Python è bizzarro a prova di errore:

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

Questo può tornare utile a volte, ma può anche portare a comportamenti piuttosto strani:

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

A seconda della tua applicazione, questo potrebbe ... o no ... essere quello che speravi lì!


Di seguito è riportato il testo della mia risposta originale. È stato utile a molte persone, quindi non volevo cancellarlo.

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

Ciò può anche chiarire la differenza tra suddivisione e indicizzazione.


246

Spiega la notazione di slice di Python

In breve, i due punti ( :) in notazione pedice ( subscriptable[subscriptarg]) make slice notazione - che ha gli argomenti opzionali start, stop, step:

sliceable[start:stop:step]

Python slicing è un modo computazionalmente veloce per accedere metodicamente a parti dei tuoi dati. Secondo me, per essere anche un programmatore Python intermedio, è un aspetto del linguaggio che è necessario conoscere.

Definizioni importanti

Per cominciare, definiamo alcuni termini:

inizio: l'indice iniziale della sezione, includerà l'elemento in questo indice a meno che non sia uguale a stop , il valore predefinito è 0, ovvero il primo indice. Se è negativo, significa iniziare gli noggetti dalla fine.

stop: l'indice finale della sezione, non include l'elemento in questo indice, il valore predefinito è la lunghezza della sequenza che viene suddivisa, cioè fino alla fine compresa.

step: la quantità con cui l'indice aumenta, il valore predefinito è 1. Se è negativo, stai tagliando l'iterabile al contrario.

Come funziona l'indicizzazione

Puoi creare uno di questi numeri positivi o negativi. Il significato dei numeri positivi è semplice, ma per i numeri negativi, proprio come gli indici in Python, conti indietro alla fine per l' inizio e l' arresto , e per il passo semplicemente decrementi l'indice. Questo esempio è tratto dal tutorial della documentazione , ma l'ho leggermente modificato per indicare a quale elemento di una sequenza fa riferimento ciascun indice:

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

Come funziona l'affettatura

Per usare la notazione di sezioni con una sequenza che la supporta, è necessario includere almeno un punto tra parentesi quadre che seguono la sequenza (che implementa effettivamente il __getitem__metodo della sequenza, secondo il modello di dati Python ).

La notazione delle sezioni funziona in questo modo:

sequence[start:stop:step]

E ricorda che ci sono impostazioni predefinite per start , stop e step , quindi per accedere alle impostazioni predefinite, lascia semplicemente fuori l'argomento.

Notare la sezione per ottenere gli ultimi nove elementi da un elenco (o qualsiasi altra sequenza che lo supporti, come una stringa) sarebbe simile a questa:

my_list[-9:]

Quando vedo questo, leggo la parte tra parentesi come "9 ° dalla fine alla fine". (In realtà, l'ho abbreviato mentalmente come "-9, on")

Spiegazione:

La notazione completa è

my_list[-9:None:None]

e per sostituire i valori predefiniti (in realtà quando stepè negativo, stopil valore predefinito è -len(my_list) - 1, quindi Noneper stop significa solo che va alla fine di qualsiasi passaggio):

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

Il colon , :, è quello che dice Python si sta dando una fetta e non un indice regolare. Ecco perché il modo idiomatico di creare una copia superficiale degli elenchi in Python 2 è

list_copy = sequence[:]

E cancellarli è con:

del my_list[:]

(Python 3 ottiene a list.copye list.clearmetodo.)

Quando stepè negativo, l'impostazione predefinita è starte stopcambia

Per impostazione predefinita, quando l' stepargomento è vuoto (o None), viene assegnato a +1.

Ma puoi passare un numero intero negativo e l'elenco (o la maggior parte degli altri divisibili standard) verrà suddiviso dalla fine all'inizio.

Pertanto una sezione negativa modificherà i valori predefiniti per startestop !

Confermando questo nella fonte

Mi piace incoraggiare gli utenti a leggere la fonte e la documentazione. Il codice sorgente per gli oggetti slice e questa logica si trova qui . Innanzitutto determiniamo se stepè negativo:

 step_is_negative = step_sign < 0;

In tal caso, il limite inferiore -1 significa che suddividiamo fino all'inizio e includendo l'inizio, e il limite superiore è la lunghezza meno 1, il che significa che iniziamo dalla fine. (Nota che la semantica di questo -1è diversa da -1quella in cui gli utenti possono passare indici in Python che indicano l'ultimo elemento.)

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

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

Altrimenti stepè positivo e il limite inferiore sarà zero e il limite superiore (a cui andiamo fino ma non includendo) la lunghezza dell'elenco a fette.

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

Quindi, potrebbe essere necessario applicare i valori predefiniti per starte stop- il valore predefinito quindi per startviene calcolato come limite superiore quando stepè negativo:

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

e stopil limite inferiore:

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

Dai un nome descrittivo alle tue sezioni!

Potresti trovare utile separare formando la sezione dal passarla al list.__getitem__metodo ( ecco cosa fanno le parentesi quadre ). Anche se non sei nuovo, mantiene il tuo codice più leggibile in modo che gli altri che potrebbero dover leggere il tuo codice possano capire più facilmente cosa stai facendo.

Tuttavia, non puoi semplicemente assegnare alcuni numeri separati da due punti a una variabile. Devi usare l'oggetto slice:

last_nine_slice = slice(-9, None)

Il secondo argomento, Noneè necessario, in modo che il primo argomento sia interpretato come startargomento, altrimenti sarebbe l' stopargomento .

È quindi possibile passare l'oggetto slice alla sequenza:

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

È interessante che le gamme prendano anche le sezioni:

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

Considerazioni sulla memoria:

Poiché sezioni di elenchi Python creano nuovi oggetti in memoria, un'altra importante funzione da tenere presente è itertools.islice. In genere ti consigliamo di scorrere su una porzione, non solo di averla creata staticamente in memoria. isliceè perfetto per questo. Un avvertimento, non supporta argomenti negativi a start, stopo step, quindi, se questo è un problema, potrebbe essere necessario calcolare gli indici o invertire l'iterabile in anticipo.

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

e adesso:

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

Il fatto che le sezioni di elenco facciano una copia è una caratteristica delle liste stesse. Se stai tagliando oggetti avanzati come Pandas DataFrame, potrebbe restituire una vista sull'originale e non una copia.


147

E un paio di cose che non sono state immediatamente ovvie per me quando ho visto per la prima volta la sintassi di taglio:

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

Un modo semplice per invertire le sequenze!

E se volessi, per qualche motivo, ogni secondo elemento nella sequenza inversa:

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

100

In Python 2.7

Affettare in 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).

Comprendere l'assegnazione dell'indice è molto importante.

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

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

Quando dici [a: b: c], stai dicendo in base al segno di c (avanti o indietro), inizia con a e termina con b (escluso l'elemento all'indice bth). Usa la regola di indicizzazione sopra e ricorda che troverai solo elementi in questo intervallo:

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

Ma questa gamma continua in entrambe le direzioni all'infinito:

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

Per esempio:

             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

Se la tua scelta di a, b e c consente la sovrapposizione con l'intervallo sopra mentre attraversi usando le regole per a, b, c sopra otterrai una lista con elementi (toccati durante l'attraversamento) o otterrai una lista vuota.

Un'ultima cosa: se aeb sono uguali, allora ottieni anche un elenco vuoto:

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

2
un altro esempio interessante: a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]; a[:-2:-2]che risulta a[9]
Deviacium il

96

Ho trovato questo fantastico tavolo su 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)

65

Dopo averlo usato un po 'mi rendo conto che la descrizione più semplice è che è esattamente la stessa degli argomenti in un forciclo ...

(from:to:step)

Ognuno di loro è facoltativo:

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

Quindi l'indicizzazione negativa deve solo aggiungere la lunghezza della stringa agli indici negativi per capirla.

Questo funziona per me comunque ...


52

Trovo più facile ricordare come funziona, e quindi riesco a capire qualsiasi combinazione specifica start / stop / step.

È istruttivo capire range()prima:

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

Inizia da start, incrementa di step, non raggiungi stop. Molto semplice.

La cosa da ricordare del passaggio negativo è che stopè sempre la fine esclusa, sia che sia superiore o inferiore. Se vuoi la stessa fetta nell'ordine opposto, è molto più pulito eseguire l'inversione separatamente: ad esempio, 'abcde'[1:-2][::-1]taglia un carattere da sinistra, due da destra, quindi inverte. (Vedi anche reversed().)

La suddivisione in sequenze è la stessa, tranne per il fatto che prima normalizza gli indici negativi e non può mai uscire dalla sequenza:

TODO : Il codice seguente aveva un bug con "mai andare fuori dalla sequenza" quando abs (step)> 1; Io penso che patchato che sia corretto, ma è difficile da capire.

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]

Non preoccuparti dei is Nonedettagli: ricorda che omettere starte / o fare stopsempre la cosa giusta per darti l'intera sequenza.

La normalizzazione degli indici negativi consente innanzitutto di contare indipendentemente l'inizio e / o l'arresto dalla fine: 'abcde'[1:-2] == 'abcde'[1:3] == 'bc'nonostante range(1,-2) == []. La normalizzazione a volte è pensata come "modulo la lunghezza", ma nota che aggiunge la lunghezza solo una volta: ad esempio 'abcde'[-53:42]è solo l'intera stringa.


3
Non this_is_how_slicing_worksè lo stesso di Python Slice. EG [0, 1, 2][-5:3:3]otterrà [0] in Python, ma list(this_is_how_slicing_works([0, 1, 2], -5, 3, 3))otterrà [1].
Eastsun,

@Eastsun Oops, hai ragione! Un caso più chiaro: range(4)[-200:200:3] == [0, 3]ma list(this_is_how_slicing_works([0, 1, 2, 3], -200, 200, 3)) == [2]. Il mio if 0 <= i < len(seq):era un tentativo di implementare "mai andare fuori dalla sequenza" semplicemente ma è sbagliato per il passaggio> 1. Lo riscriverò più tardi oggi (con i test).
Beni Cherniavsky-Paskin,

40

Uso il metodo "un indice indica tra gli elementi" per pensarci da solo, ma un modo per descriverlo che a volte aiuta gli altri a ottenerlo è questo:

mylist[X:Y]

X è l'indice del primo elemento desiderato.
Y è l'indice del primo elemento che non vuoi.


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

Spero che questo ti aiuti a modellare l'elenco in Python.

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


38

Notazione di slicing Python:

a[start:end:step]
  • Per starte end, i valori negativi sono interpretati come relativi alla fine della sequenza.
  • Gli indici positivi per endindicano la posizione dopo l'ultimo elemento da includere.
  • I valori vuoti sono in default come segue: [+0:-0:1].
  • L'uso di un passaggio negativo inverte l'interpretazione di starteend

La notazione si estende a matrici (intorpidite) e matrici multidimensionali. Ad esempio, per tagliare intere colonne è possibile utilizzare:

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

Le sezioni contengono riferimenti, non copie, degli elementi dell'array. Se si desidera creare una copia separata di un array, è possibile utilizzare deepcopy().


34

Puoi anche utilizzare l'assegnazione delle sezioni per rimuovere uno o più elementi da un elenco:

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

33

Questo è solo per alcune informazioni extra ... Considera l'elenco qui sotto

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

Pochi altri trucchi per invertire la lista:

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

33

Ecco come insegno le sezioni ai neofiti:

Comprensione della differenza tra indicizzazione e suddivisione:

Wiki Python ha questa fantastica immagine che distingue chiaramente indicizzazione e suddivisione.

Inserisci qui la descrizione dell'immagine

È un elenco con sei elementi al suo interno. Per capire meglio l'affettamento, considera tale elenco come un insieme di sei caselle messe insieme. Ogni scatola contiene un alfabeto.

L'indicizzazione è come gestire il contenuto della scatola. Puoi controllare il contenuto di qualsiasi casella. Ma non puoi controllare il contenuto di più caselle contemporaneamente. Puoi persino sostituire il contenuto della confezione. Ma non puoi posizionare due palline in una scatola o sostituire due palline alla volta.

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

Affettare è come gestire le scatole stesse. Puoi prendere la prima scatola e posizionarla su un altro tavolo. Per prendere la scatola, tutto ciò che devi sapere è la posizione di inizio e fine della scatola.

Puoi anche raccogliere le prime tre caselle o le ultime due caselle o tutte le caselle tra 1 e 4. Quindi, puoi scegliere qualsiasi set di caselle se conosci l'inizio e la fine. Queste posizioni sono denominate posizioni iniziale e finale.

La cosa interessante è che puoi sostituire più caselle contemporaneamente. Inoltre puoi posizionare più caselle dove preferisci.

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

Affettare con passaggio:

Fino ad ora hai scelto le scatole continuamente. Ma a volte devi raccogliere discretamente. Ad esempio, puoi ritirare ogni seconda casella. Puoi anche ritirare ogni terza scatola dalla fine. Questo valore è chiamato dimensione del gradino. Questo rappresenta il divario tra i tuoi successivi pickup. La dimensione del passo dovrebbe essere positiva se si selezionano caselle dall'inizio alla fine e viceversa.

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

Come Python calcola i parametri mancanti:

Quando si taglia, se si lascia fuori qualsiasi parametro, Python prova a capirlo automaticamente.

Se controlli il codice sorgente di CPython , troverai una funzione chiamata PySlice_GetIndicesEx () che calcola gli indici in una sezione per ogni dato parametro. Ecco il codice logico equivalente in Python.

Questa funzione accetta un oggetto Python e parametri opzionali per lo slicing e restituisce l'inizio, l'arresto, il passo e la lunghezza dello slice per lo slice richiesto.

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)

Questa è l'intelligenza che è presente dietro le sezioni. Poiché Python ha una funzione integrata chiamata slice, è possibile passare alcuni parametri e verificare in che modo calcola i parametri mancanti.

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]

Nota: questo post è stato originariamente scritto nel mio blog, The Intelligence Behind Python Slices .


29

Come regola generale, la scrittura di codice con molti valori di indice hardcoded porta a problemi di leggibilità e manutenzione. Ad esempio, se torni al codice un anno dopo, lo guarderai e ti chiederai cosa stavi pensando quando lo hai scritto. La soluzione mostrata è semplicemente un modo per affermare più chiaramente cosa sta realmente facendo il tuo codice. In generale, lo slice () incorporato crea un oggetto slice che può essere utilizzato ovunque sia consentita una slice. Per esempio:

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

Se si dispone di un'istanza di slice, è possibile ottenere ulteriori informazioni su di essa osservando rispettivamente i relativi attributi s.start, s.stop e s.step. Per esempio:

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

25

1. Notazione delle sezioni

Per semplificare, ricorda che slice ha una sola forma :

s[start:end:step]

ed ecco come funziona:

  • s: un oggetto che può essere tagliato
  • start: primo indice per avviare l'iterazione
  • end: ultimo indice, NOTA che l' endindice non verrà incluso nella sezione risultante
  • step: seleziona l'elemento ogni stepindice

Un'altra cosa di importazione: tutti start, end, steppuò essere omesso! E se sono omessi, il loro valore di default verrà utilizzato: 0, len(s), 1di conseguenza.

Quindi le possibili variazioni sono:

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

NOTA: Se start >= end(considerando solo quando step>0), Python restituirà una sezione vuota [].

2. Insidie

La parte precedente spiega le funzionalità principali su come funziona lo slice e funzionerà nella maggior parte dei casi. Tuttavia, ci possono essere insidie ​​da tenere d'occhio e questa parte le spiega.

Indici negativi

La prima cosa che confonde gli studenti di Python è che un indice può essere negativo! Niente panico: un indice negativo significa contare all'indietro.

Per esempio:

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

Passo negativo

Rendere le cose più confuse è che steppuò essere anche negativo!

Un passaggio negativo significa iterare l'array all'indietro: dalla fine all'inizio, con l'indice di fine incluso e l'indice di inizio escluso dal risultato.

NOTA : quando il passaggio è negativo, il valore predefinito per startè len(s)(mentre endnon è uguale a 0, perché s[::-1]contiene s[0]). Per esempio:

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

Errore fuori portata?

Sorprendi: lo slice non genera un IndexError quando l'indice è fuori portata!

Se l'indice non è compreso nell'intervallo, Python farà del suo meglio per impostare l'indice su 0o in len(s)base alla situazione. Per esempio:

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

Finiamo questa risposta con esempi, spiegando tutto ciò di cui abbiamo discusso:

# 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

24

Le risposte precedenti non trattano la suddivisione in array multidimensionale che è possibile utilizzando il famoso pacchetto NumPy :

L'affettatura può essere applicata anche ad array multidimensionali.

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

Il " :2" prima della virgola opera sulla prima dimensione e il " 0:3:2" dopo la virgola opera sulla seconda dimensione.


4
Solo un promemoria per ricordare che non puoi farlo su Python listma solo su arrayNumpy
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)

Puoi eseguire questo script e sperimentarlo, di seguito sono riportati alcuni esempi che ho ottenuto dallo script.

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

Quando si utilizza un passaggio negativo, notare che la risposta viene spostata a destra di 1.


14

Il mio cervello sembra felice di accettare che lst[start:end]contenga l' startennesimo oggetto. Potrei anche dire che si tratta di un "presupposto naturale".

Ma ogni tanto si insinua un dubbio e il mio cervello chiede rassicurazione che non contenga l' endennesimo elemento.

In questi momenti mi affido a questo semplice teorema:

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

Questa bella proprietà mi dice che lst[start:end]non contiene l' endelemento -th perché è dentrolst[end:] .

Nota che questo teorema è vero per ntutti. Ad esempio, puoi verificarlo

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

ritorna True.


12

Secondo me, capirai e memorizzerai meglio la notazione di suddivisione in stringhe di Python se la guardi nel modo seguente (continua a leggere).

Lavoriamo con la seguente stringa ...

azString = "abcdefghijklmnopqrstuvwxyz"

Per coloro che non lo sanno, è possibile creare qualsiasi sottostringa azStringusando la notazioneazString[x:y]

Proveniente da altri linguaggi di programmazione, è allora che il buon senso viene compromesso. Cosa sono xey?

Ho dovuto sedermi e correre diversi scenari nella mia ricerca di una tecnica di memorizzazione che mi aiuterà a ricordare cosa sono xey e mi aiuterà a tagliare correttamente le stringhe al primo tentativo.

La mia conclusione è che xey dovrebbero essere visti come gli indici di confine che circondano le stringhe che vogliamo aggiungere. Quindi dovremmo vedere l'espressione come azString[index1, index2]o ancora più chiara come azString[index_of_first_character, index_after_the_last_character].

Ecco un esempio di visualizzazione di quello ...

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

Quindi tutto ciò che devi fare è impostare index1 e index2 sui valori che circonderanno la sottostringa desiderata. Ad esempio, per ottenere la sottostringa "cdefgh", è possibile utilizzareazString[2:8] , poiché l'indice sul lato sinistro di "c" è 2 e quello sulla dimensione giusta di "h" è 8.

Ricorda che stiamo definendo i confini. E quei confini sono le posizioni in cui è possibile posizionare alcune parentesi che verranno avvolte attorno alla sottostringa in questo modo ...

ab [ cdefgh ] ij

Quel trucco funziona sempre ed è facile da memorizzare.


11

La maggior parte delle risposte precedenti chiarisce le domande sulla notazione delle sezioni.

La sintassi di indicizzazione estesa utilizzata per il slicing è aList[start:stop:step]ed esempi di base sono:

Inserisci qui la descrizione dell'immagine:

Altri esempi di affettatura: 15 fette estese


10

In Python, il modulo più semplice per tagliare è il seguente:

l[start:end]

dove lc'è una raccolta, startè un indice inclusivo ed endè un indice esclusivo.

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]

Quando si esegue il slicing dall'inizio, è possibile omettere l'indice zero e, se si esegue il slicing fino alla fine, è possibile omettere l'indice finale poiché è ridondante, quindi non essere prolisso:

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

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

Gli interi negativi sono utili quando si eseguono offset relativi alla fine di una raccolta:

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]

È possibile fornire indici fuori limite durante il taglio come:

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]

Tieni presente che il risultato dell'affettatura di una raccolta è una raccolta completamente nuova. Inoltre, quando si utilizza la notazione delle sezioni nelle assegnazioni, la lunghezza delle assegnazioni delle sezioni non deve essere la stessa. I valori prima e dopo la sezione assegnata verranno mantenuti e la raccolta si ridurrà o crescerà per contenere i nuovi valori:

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]

Se si omette l'indice di inizio e fine, verrà creata una copia della raccolta:

In [14]: l_copy = l[:]

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

Se gli indici di inizio e fine vengono omessi durante l'esecuzione di un'operazione di assegnazione, l'intero contenuto della raccolta verrà sostituito con una copia di ciò a cui viene fatto riferimento:

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

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

Oltre all'affettatura di base, è anche possibile applicare la seguente notazione:

l[start:end:step]

dove si ltrova una raccolta, startè un indice inclusivo, endè un indice esclusivo ed stepè un passo che può essere utilizzato per includere ogni ennesimo elemento 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]

L'utilizzo stepfornisce un trucco utile per invertire una raccolta in Python:

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

È anche possibile utilizzare numeri interi negativi stepcome nell'esempio seguente:

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

Tuttavia, l'utilizzo di un valore negativo per steppotrebbe diventare molto confuso. Inoltre, al fine di essere Pythonic , si dovrebbe evitare di utilizzare start, ende stepin una sola fetta. Nel caso sia necessario, considera di farlo in due compiti (uno da tagliare e l'altro da percorrere).

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

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

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

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

10

Voglio aggiungerne uno Ciao, Mondo! esempio che spiega le basi delle sezioni per i principianti. Mi ha aiutato molto.

Facciamo un elenco con sei valori ['P', 'Y', 'T', 'H', 'O', 'N']:

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

Ora le sezioni più semplici di tale elenco sono le sue liste secondarie. La notazione è [<index>:<index>]e la chiave è leggerlo in questo modo:

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

Ora se fai una fetta [2:5]dell'elenco sopra, questo accadrà:

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

Hai effettuato un taglio prima dell'elemento con indice 2e un altro taglio prima dell'elemento con indice 5. Quindi il risultato sarà una fetta tra quei due tagli, un elenco ['T', 'H', 'O'].


10

Personalmente ci penso come un forciclo:

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

Inoltre, si noti che i valori negativi per starte endsono relativi alla fine dell'elenco e calcolati nell'esempio sopra da given_index + a.shape[0].


8

Di seguito è riportato l'esempio di un indice di una stringa:

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

str="Name string"

Esempio di affettatura: [inizio: fine: passaggio]

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 seguito è riportato l'uso di esempio:

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

5

Se ritieni che gli indici negativi nel taglio siano confusi, ecco un modo molto semplice di pensarci: sostituisci semplicemente l'indice negativo con len - index. Ad esempio, sostituire -3 con len(list) - 3.

Il modo migliore per illustrare ciò che lo slicing fa internamente è semplicemente mostrarlo nel codice che implementa questa operazione:

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

4

La tecnica di taglio di base consiste nel definire il punto iniziale, il punto di arresto e la dimensione del passo, noto anche come passo.

Innanzitutto, creeremo un elenco di valori da utilizzare nella nostra suddivisione.

Crea due elenchi da tagliare. Il primo è un elenco numerico da 1 a 9 (Elenco A). Il secondo è anche un elenco numerico, da 0 a 9 (Elenco 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)

Indicizza il numero 3 da A e il numero 6 da B.

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

Affettatura di base

La sintassi di indicizzazione estesa utilizzata per lo slicing è aList [start: stop: step]. L'argomento start e l'argomento step sono entrambi predefiniti su none - l'unico argomento richiesto è stop. Hai notato che è simile a come è stato utilizzato l'intervallo per definire gli elenchi A e B? Questo perché l'oggetto slice rappresenta l'insieme di indici specificato dall'intervallo (start, stop, step). Documentazione di Python 3.4.

Come puoi vedere, la definizione di solo stop restituisce un elemento. Poiché l'avvio non è impostato su nessuno, questo si traduce nel recupero di un solo elemento.

È importante notare che il primo elemento è l'indice 0, non indice 1. Questo è il motivo per cui stiamo usando 2 elenchi per questo esercizio. Gli elementi dell'elenco A sono numerati in base alla posizione ordinale (il primo elemento è 1, il secondo elemento è 2, ecc.) Mentre gli elementi dell'elenco B sono i numeri che verrebbero utilizzati per indicizzarli ([0] per il primo elemento 0, eccetera.).

Con una sintassi di indicizzazione estesa, recuperiamo un intervallo di valori. Ad esempio, tutti i valori vengono recuperati con due punti.

A[:]

Per recuperare un sottoinsieme di elementi, è necessario definire le posizioni iniziale e finale.

Dato il modello aList [start: stop], recupera i primi due elementi dall'elenco A.


3

Non penso che il diagramma tutorial di Python (citato in varie altre risposte) sia buono in quanto questo suggerimento funziona per il passo positivo, ma non per un passo negativo.

Questo è il diagramma:

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

Dal diagramma, mi aspetto a[-4,-6,-1]di esserlo yPma lo è ty.

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

Quello che funziona sempre è pensare nei caratteri o negli slot e usare l'indicizzazione come intervallo semiaperto: apertura a destra se falcata positiva, apertura a sinistra se falcata negativa.

In questo modo, posso pensare a a[-4:-6:-1]come a(-6,-4]nella terminologia intervallo.

 +---+---+---+---+---+---+
 | 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  
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.