list slice - Comprendere la notazione delle sezioni di Python




string operator (25)

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

Per me, questa notazione ha bisogno di un po 'di ripresa.

Sembra estremamente potente, ma non ho ancora capito la cosa.


Answers

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 aiuterà a modellare la lista in Python.

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


Fetta : - il serpente appare vicino al tuo piede. Si sposta dall'invisibile al visibile. La nostra visione rivela (come una fetta) solo una parte del mondo. analogamente una slice Python estrae gli elementi, basandosi su un inizio e uno stop. Prendiamo fette su molti tipi in Python. Specifichiamo un primo indice facoltativo, un ultimo indice facoltativo e un passaggio facoltativo.

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

puoi ottenere dei buoni esempi al link qui sotto: - esempio di notazione di slice python


1. Notazione della fetta

Per semplificare, ricorda che slice ha una sola forma:

s[start:end:step]

ed ecco come funziona:

  • s : un oggetto che può essere affettato
  • start : primo indice per iniziare l'iterazione
  • end : ultimo indice, NOTA che l'indice end non sarà incluso nella fetta risultante
  • step : scegli l'elemento ogni indice di step

Un'altra cosa importante: tutto start , end , step può essere omesso! E se vengono omessi, verrà utilizzato il loro valore predefinito: 0 , len(s) , 1 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 il step>0 ), python restituirà una slice vuota [] .

2. Insidie

La parte sopra spiega le caratteristiche principali su come funziona la fetta, funzionerà nella maggior parte delle occasioni. Tuttavia ci possono essere delle insidie ​​che dovresti fare attenzione, e questa parte le spiega.

Indici negativi

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

Per esempio:

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

Passo negativo

Rendere le cose più confuse è che anche questo step può essere negativo!

Il passo negativo significa iterare l'array all'indietro: dalla fine all'inizio, con l'indice finale incluso, e iniziare l'indice escluso dal risultato.

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

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

Errore fuori intervallo?

Essere sorpreso: slice non genera IndexError quando l'indice non è compreso nell'intervallo!

Se l'indice non rientra nell'intervallo, python proverà al meglio impostando l'indice su 0 o len(s) base alla situazione. Per esempio:

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

3. Esempi

Finiamo questa risposta con esempi che spiegano 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, python will set it to len(s)
Out[12]: [3, 4, 5, 6, 7, 8, 9]

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

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

IndexError: list index out of range

Hehehe, è piuttosto strano vedermi cercare di fornire una spiegazione migliore e più semplice dopo 2600+ voti su ciò che è stato contrassegnato come la risposta giusta da Grew Hewgill.

Eccoci qui ...

Secondo me, capirai e imparerai meglio la notazione di slicing delle stringhe di Python se la guardi nel seguente modo (continua a leggere).

Lavoriamo con la seguente stringa ...

azString = "abcdefghijklmnopqrstuvwxyz"

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

Venendo da altri linguaggi di programmazione, questo è il momento in cui il buon senso viene compromesso. Cosa sono x e y?

Ho dovuto sedermi e fare diversi scenari nella mia ricerca di una tecnica di memorizzazione che mi aiuterà a ricordare che cosa sono x e y aiutarmi 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 anche più chiara come azString[index_of_first_character, index_after_the_last_character].

Ecco un esempio di visualizzazione di quello ...

Letters abcdefghij ... ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ Indexes 0 1 2 3 4 5 6 7 8 9 ... | | cdefgh index1 index2

Quindi tutto quello che devi fare se vuoi impostare index1 e index2 sui valori che circonderanno la sottostringa desiderata. Ad esempio, per ottenere la sottostringa "cdefgh", puoi usare azString[2:8]perché l'indice sul lato sinistro di "c" è 2 e quello sulla dimensione giusta di "h" è 8.

Ricorda, stiamo impostando i confini.

Quel trucco funziona tutto il tempo ed è facile da memorizzare.

Spero che questo ti possa aiutare.


Questo è il modo in cui insegno ai neofiti:

Comprensione della differenza tra indicizzazione e affettatura:

Wiki Python ha questa fantastica immagine che distingue chiaramente l'indicizzazione e l'affettatura.

È una lista con 6 elementi. Per capire meglio l'affettamento, considera quell'elenco come un insieme di sei scatole messe insieme. Ogni scatola contiene un alfabeto.

L'indicizzazione è come trattare con il contenuto della scatola. Puoi controllare il contenuto di qualsiasi scatola. Ma non è possibile controllare il contenuto di più caselle contemporaneamente. Puoi anche sostituire il contenuto della scatola. Ma non puoi piazzare 2 palle in 1 scatola o sostituire 2 palle 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 trattare con le scatole stesse. Puoi ritirare la prima casella e posizionarla su un altro tavolo. Per raccogliere la scatola tutto quello che devi sapere è la posizione di inizio e fine della scatola.

Puoi persino selezionare le prime 3 caselle o le ultime 2 caselle o tutte le caselle tra 1 e 4. Quindi, puoi selezionare qualsiasi set di caselle se conosci l'inizio e la fine. Queste posizioni sono chiamate posizioni di start & stop.

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

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

Fino ad ora hai scelto le scatole continuamente. Ma a volte devi riprenderti discretamente. Ad esempio È possibile raccogliere ogni seconda casella. Puoi persino ritirare ogni terza scatola dalla fine. Questo valore è chiamato dimensione del passo. Questo rappresenta il divario tra i tuoi successivi pickup. La dimensione del passo dovrebbe essere positiva se stai selezionando 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 affetta se si omette qualsiasi parametro, Python prova a capirlo automaticamente.

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

Questa funzione accetta un oggetto Python e parametri opzionali per l'affettatura e restituisce la lunghezza iniziale, finale, di passo e fetta per la fetta richiesta.

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 fette. Dato che Python ha una funzione incorporata chiamata slice, puoi passare alcuni parametri e verificare in che misura calcola in modo intelligente 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 http://www.avilpage.com/2015/03/a-slice-of-python-intelligence-behind.html


Questo è solo per alcune informazioni extra ... Considera la lista 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]

Vedi la risposta di abc sopra


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

Capire 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 a seconda del segno di c (in avanti o indietro), inizia da a e termina in b (escluso l'elemento in bth index). Utilizza 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 di sovrapporsi all'intervallo sopra mentre attraversi le regole per a, b, c sopra, otterrai una lista con elementi (toccati durante il percorso) o otterrai una lista vuota.

Un'ultima cosa: se a e b sono uguali, allora ottieni anche una lista vuota:

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

Puoi anche utilizzare l'assegnazione di 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]

È davvero semplice:

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

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

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

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

L'altra caratteristica è che l' start o la end può essere un numero negativo , il che significa che conta dalla fine dell'array invece che 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, il step potrebbe 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 oggetti di quelli che chiedi. Ad esempio, se chiedi a[:-2] e a solo contiene un elemento, ottieni un elenco vuoto invece di un errore. A volte preferiresti l'errore, quindi devi essere consapevole che questo può accadere.


Il mio cervello sembra felice di accettare che lst[start:end]contenga l' startelemento -th. Potrei anche dire che è un "presupposto naturale".

Ma a volte un dubbio si insinua e il mio cervello chiede rassicurazione sul fatto che non contenga l' endelemento -th.

In questi momenti mi affido a questo semplice teorema:

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

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

Si noti che questo teorema è vero per alcuno n. Ad esempio, puoi verificarlo

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

ritorna True .


E un paio di cose che non erano immediatamente ovvie per me quando ho visto per la prima volta la sintassi slicing:

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

Un modo semplice per invertire le sequenze!

E se volevi, per qualche motivo, ogni secondo elemento nella sequenza invertita:

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

La maggior parte delle risposte di cui sopra cancella la notazione Slice. Sintassi di indicizzazione estesa utilizzata per l'affettatura sono aList[start:stop:step]esempi di base

:

Altri esempi di fette : 15 fette estese


Il tutorial su Python ne parla (scorri un po 'fino a quando non arrivi alla parte relativa al taglio).

Il diagramma artistico ASCII è utile anche per ricordare come funzionano le fette:

 +---+---+---+---+---+---+
 | 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 fette è pensare agli indici come a indicare tra i caratteri, con il bordo sinistro del primo carattere numerato 0. Quindi il margine destro dell'ultimo carattere di una stringa di n caratteri ha indice n .


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

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

Se il stride è negativo, l'ordine viene modificato un po '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]]

L'affettamento esteso (con virgole ed ellissi) viene principalmente utilizzato solo da strutture dati speciali (come Numpy); le sequenze di base non li supportano.

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

Di seguito è riportato l'esempio di 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 taglio: [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'utilizzo 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

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

(from:to:step)

qualcuno di loro è facoltativo

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

quindi l'indicizzazione negativa ha solo bisogno di aggiungere la lunghezza della stringa agli indici negativi per comprenderla.

Questo funziona comunque per me ...


La tecnica di base per l'affettatura consiste nel definire il punto di partenza, il punto di arresto e la dimensione del passo, noto anche come falcata.

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

Crea due liste da affettare, la prima è una lista numerica 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,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])

Slicing di base

La sintassi di indicizzazione estesa utilizzata per il taglio è una lista [start: stop: step]. L'argomento start e l'argomento step sono entrambi predefiniti su none - l'unico argomento richiesto è stop. Hai notato che questo è 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 da intervallo (start, stop, step). Documentazione di Python 3.4

Come puoi vedere, la definizione di solo stop restituisce un elemento. Dal momento che l'avvio è impostato su none, questo si traduce nel recupero di un solo elemento.

È importante notare che il primo elemento è l'indice 0, NON l'indice 1. Ecco perché utilizziamo 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 verranno utilizzati per indicizzarli ([0] per il primo elemento 0, ecc. ).

Con la 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 di inizio e fine.

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


Le risposte sopra non discutono l'assegnazione delle fette. Per capire l'assegnazione delle sezioni, è utile aggiungere un altro concetto alla tecnica 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']

Un'euristica è, per una fetta da zero a n, pensa: "zero è l'inizio, inizia all'inizio e prendi n elementi in una lista".

>>> 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'altra euristica è, "per ogni slice, sostituire l'inizio con zero, applicare l'euristica precedente per ottenere la fine dell'elenco, quindi contare il primo numero per ritagliare gli elementi dall'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é slicing 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 dell'assegnazione delle sezioni, che puoi anche vedere sopra, è che qualunque porzione della lista viene restituita dall'indicizzazione delle sezioni, è 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 dell'assegnazione delle sezioni è che l'elenco assegnato (iterabile) non deve avere la stessa lunghezza; la porzione indicizzata viene semplicemente affettata e sostituita in massa da qualunque 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 da abituare è l'assegnazione a sezioni vuote. Usando l'euristica 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, anche l'assegnazione delle slice alla slice vuota ha senso:

>>> 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'] # result is longer
>>> p = ['P','y','t','h','o','n']
>>> p[4:4] = ['x','y']
>>> p
 ['P','y','t','h','x','y','o','n'] # result is longer still

Nota che, dato che non stiamo cambiando il secondo numero della slice (4), gli elementi inseriti si accumulano sempre contro la 'o', anche quando ci stiamo assegnando alla slice vuota. Quindi la posizione per l'assegnazione di slice vuota è l'estensione logica delle posizioni per le assegnazioni di slice non vuote.

Eseguendo il backup un po ', cosa succede quando continui con la nostra processione di conteggio all'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 affettare, una volta che hai finito, hai finito; non inizia a tagliare all'indietro. In Python non si ottengono passi falsi negativi a meno che non vengano richiesti esplicitamente usando un numero negativo.

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

Ci sono alcune strane conseguenze per la 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, paragonato all'indicizzazione, l'affettatura python è bizzarramente a prova di errore:

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

Questo può tornare utile a volte, ma può anche portare a un comportamento un po 'strano:

>>> 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 dell'applicazione, potrebbe ... o potrebbe non ... essere quello che speravi lì!

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

>>> r=[0,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 affettatura e indicizzazione.


Se senti che gli indici negativi nell'affettare sono confusi, ecco un modo molto semplice per pensarci: basta sostituire l'indice negativo con len - index. Ad esempio, sostituisci -3 con len(list) - 3.

Il modo migliore per illustrare ciò che affetta 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 for-loop with start, end and step
  return [list[i] for i in range(start, end, step)]

Voglio aggiungere un esempio Hello world che spiega le basi delle sezioni per i principianti. Mi ha aiutato molto.

Abbiamo una lista con sei valori ['P', 'Y', 'T', 'H', 'O', 'N']:

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

Ora le fette più semplici di quella lista sono le sue sottoliste. La notazione è [<index>:<index>]e la chiave è leggerla in questo modo:

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

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

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

Hai fatto 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, una lista ['T', 'H', 'O'].


Trovo più facile ricordare come funziona, quindi riesco a capire una combinazione specifica di avvio / arresto / passaggio.

È 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

Comincia start , incrementa per step , non raggiungere l' stop . Molto semplice.

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

L'affettamento della sequenza è lo stesso, tranne che per prima cosa normalizza gli indici negativi e non può mai uscire dalla sequenza:

TODO : Il codice sotto aveva un bug con "mai andare fuori dalla sequenza" quando abs (step)> 1; Penso di aver corretto le patch per essere 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 del fatto che non ci is None dettagli - ricorda solo che omettendo start e / o stop fa sempre la cosa giusta per darti l'intera sequenza.

Normalizzare gli indici negativi per prima cosa consente di iniziare indipendentemente dalla fine e / o dallo stop: 'abcde'[1:-2] == 'abcde'[1:3] == 'bc' nonostante la range(1,-2) == [] . La normalizzazione a volte viene considerata come "modulo la lunghezza", ma si noti che aggiunge la lunghezza una sola volta: ad esempio 'abcde'[-53:42] è solo l'intera stringa.


Le risposte di cui sopra non parlano dell'affiancamento multidimensionale dell'array che è possibile usando il famoso pacchetto numpy:

La segmentazione si applica anche agli array multi-dimensionali.

# 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 funziona sulla prima dimensione e su "0: 3: 2" dopo che la virgola è attiva sulla seconda dimensione.


In Python, la forma più semplice per affettare è la seguente:

l[start:end]

dove lè 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 affetta dall'inizio, è possibile omettere l'indice zero e, quando si affetta 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 gli offset rispetto 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 3 elements
Out[8]: [7, 8, 9]

È possibile fornire indici che sono fuori limite quando si affetta come:

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

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

Tieni presente che il risultato dell'affettare una collezione è una collezione completamente nuova. Inoltre, quando si utilizza la notazione delle sezioni nelle assegnazioni, non è necessario che la lunghezza dell'assegnazione delle sezioni sia uguale. I valori prima e dopo la porzione assegnata verranno mantenuti e la raccolta si ridurrà o aumenterà per contenere i nuovi valori:

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

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

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

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

Se ometti l'indice di inizio e fine, creerai 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 di fine sono omessi quando si esegue un'operazione di assegnazione, l'intero contenuto della raccolta verrà sostituito con una copia di ciò a cui si fa riferimento:

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

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

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

l[start:end:step]

dove lè una collezione, startè un indice inclusivo, endè un indice esclusivo, ed stepè un passo che può essere usato per prendere ogni ennesimo elemento in 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'uso stepfornisce un trucco utile per invertire una collezione 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 steppotrebbe diventare molto confuso. Inoltre, al fine di essere Pythonic, si dovrebbe evitare di utilizzare start, ende stepin una sola fetta. Nel caso in cui ciò sia richiesto, si consideri di farlo in due compiti (uno da affettare 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]

Spiega la notazione delle sezioni di Python

In breve, i due punti (:) nella notazione subscript ( subscriptable[subscriptarg] ) rendono la notazione slice - che ha gli argomenti opzionali, start , stop , step :

sliceable[start:stop:step]

Python slicing è un modo computazionalmente veloce per accedere in modo metodico a parti dei tuoi dati. Secondo me, per essere anche un programmatore Python intermedio, è un aspetto della lingua che è necessario conoscere.

Definizioni importanti

Per cominciare, definiamo alcuni termini:

start: l'indice iniziale della slice, includerà l'elemento in questo indice a meno che non sia lo stesso di stop , il valore predefinito è 0, ovvero il primo indice. Se è negativo, significa iniziare n elementi dalla fine.

stop: l'indice finale della slice, non include l'elemento in questo indice, ha come valore predefinito la lunghezza della sequenza da tagliare, cioè fino alla fine inclusa.

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

Come funziona l'indicizzazione

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

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

Come funziona il taglio

Per utilizzare la notazione di sezione con una sequenza che la supporta, è necessario includere almeno un punto tra parentesi quadre che seguono la sequenza (che implementa effettivamente il metodo __getitem__ della sequenza, in base al modello di dati Python .)

La notazione Slice funziona così:

sequence[start:stop:step]

E ricorda che ci sono dei valori predefiniti per start , stop e step , quindi per accedere ai valori predefiniti, basta lasciare fuori l'argomento.

La notazione Slice per ottenere gli ultimi nove elementi da una lista (o qualsiasi altra sequenza che la supporta, come una stringa) è simile alla seguente:

my_list[-9:]

Quando vedo questo, leggo la parte tra parentesi come "9 dalla fine alla fine". (In realtà, lo abbrevia mentalmente come "-9, in")

Spiegazione:

La notazione completa è

my_list[-9:None:None]

e per sostituire i valori predefiniti (in realtà quando il step è negativo, il valore predefinito di -len(my_list) - 1 è -len(my_list) - 1 , quindi None per l'arresto in realtà significa solo che va a qualsiasi punto finale lo porti a:

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

Il colon , : , è ciò che dice a Python che gli stai dando una fetta e non un indice regolare. Ecco perché il modo idiomatico di fare una copia superficiale delle liste in Python 2 è

list_copy = sequence[:]

E chiarirli è con:

del my_list[:]

(Python 3 ottiene un metodo list.copy e list.clear ).

Quando il step è negativo, i valori predefiniti per l' start e l' stop cambiano

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

Ma è possibile passare un intero negativo e la lista (o la maggior parte degli altri standard affettabili) verrà tagliata dalla fine all'inizio.

Quindi una fetta negativa cambierà i valori predefiniti per l' start e l' stop !

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 . Per prima cosa determiniamo se il step è negativo:

 step_is_negative = step_sign < 0;

Se è così, il limite inferiore è -1 ovvero lo dividiamo fino a comprendere l'inizio, e il limite superiore è la lunghezza meno 1, il che significa che iniziamo alla fine. (Si noti che la semantica di questo -1 è diversa da -1 che gli utenti possono passare gli indici in Python indicando 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 il step è positivo, e il limite inferiore sarà zero e il limite superiore (che andremo fino ma non includendo) la lunghezza della lista affettata.

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

Quindi, potremmo aver bisogno di applicare i valori di default per start e stop : il valore predefinito per start è calcolato come limite superiore quando il step è negativo:

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

e stop , il limite inferiore:

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

Dai alle tue fette un nome descrittivo!

Potresti trovare utile separare la forma della slice dal list.__getitem__ alla list.__getitem__ metodo list.__getitem__ ( questo è ciò che fanno le parentesi quadre ). Anche se non sei nuovo, mantiene il tuo codice più leggibile in modo che altri che potrebbero dover leggere il tuo codice possano capire più facilmente cosa stai facendo.

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

last_nine_slice = slice(-9, None)

Il secondo argomento, None , è obbligatorio, in modo che il primo argomento sia interpretato come argomento di start , altrimenti sarebbe l'argomento stop .

È quindi possibile passare l'oggetto porzione alla sequenza:

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

È interessante che anche gli intervalli prendano a fette:

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

Considerazioni sulla memoria:

Poiché le sezioni di elenchi Python creano nuovi oggetti in memoria, un'altra funzione importante da tenere presente è itertools.islice . In genere si vorrà eseguire un'iterazione su una porzione, non solo averla creata staticamente in memoria. islice è perfetto per questo. Un avvertimento, non supporta argomenti negativi per l' start , l' stop o il 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 porzioni di lista facciano una copia è una caratteristica delle liste stesse. Se stai affettando oggetti avanzati come Pandas DataFrame, potrebbe restituire una vista sull'originale e non una copia.


So che questa è una vecchia domanda, ma nel caso qualcuno come me cerchi risposte:

>>> A[5-1::-1]
[4, 3, 2, 1, 0]

>>> A[4:1:-1]
[4, 3, 2]




python list slice