Slice-Notation verstehen

3283

Ich brauche eine gute Erklärung (Referenzen sind ein Plus) für Pythons Slice-Notation.

Für mich muss diese Notation etwas aufgegriffen werden.

Es sieht extrem mächtig aus, aber ich habe es nicht ganz verstanden.

Simon
quelle

Antworten:

4501

Es ist wirklich ziemlich einfach:

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

Es gibt auch den stepWert, der mit einem der oben genannten Werte verwendet werden kann:

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

Der wichtigste Punkt, an den Sie sich erinnern sollten, ist, dass der :stopWert den ersten Wert darstellt, der sich nicht im ausgewählten Slice befindet. Der Unterschied zwischen stopund startist also die Anzahl der ausgewählten Elemente (wenn step1 ist, die Standardeinstellung).

Das andere Merkmal ist, dass startoder stopkann eine negative Zahl sein, was bedeutet, dass sie vom Ende des Arrays statt vom Anfang zählt. Damit:

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

Ebenso stepkann eine negative Zahl sein:

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 ist freundlich zum Programmierer, wenn es weniger Elemente gibt, als Sie verlangen. Wenn Sie beispielsweise nach einem Element fragen a[:-2]und es anur enthalten, erhalten Sie anstelle eines Fehlers eine leere Liste. Manchmal würden Sie den Fehler bevorzugen, daher müssen Sie sich bewusst sein, dass dies passieren kann.

Beziehung zum slice()Objekt

Der Slicing-Operator []wird im obigen Code tatsächlich mit einem slice()Objekt verwendet, das die :Notation verwendet (die nur innerhalb gültig ist []), dh:

a[start:stop:step]

ist äquivalent zu:

a[slice(start, stop, step)]

Slice-Objekte verhalten sich je nach Anzahl der Argumente ebenfalls leicht unterschiedlich, ähnlich wie range()beide, slice(stop)und slice(start, stop[, step])werden unterstützt. Um die Angabe eines bestimmten Arguments zu überspringen, könnte man verwenden None, so dass zB a[start:]äquivalent zu a[slice(start, None)]oder a[::-1]äquivalent zu ist a[slice(None, None, -1)].

Während die :Notation auf Basis des einfachen Schneidens sehr hilfreich ist, slice()vereinfacht die explizite Verwendung von Objekten die programmatische Erzeugung des Schneidens.

Greg Hewgill
quelle
122
Das Schneiden von integrierten Typen gibt eine Kopie zurück, aber das ist nicht universell. Insbesondere beim Schneiden von NumPy-Arrays wird eine Ansicht zurückgegeben, die den Speicher mit dem Original teilt.
Beni Cherniavsky-Paskin
43
Dies ist eine schöne Antwort mit den Stimmen, um dies zu beweisen, aber eines fehlt: Sie können Nonejeden der leeren Räume ersetzen . Zum Beispiel [None:None]macht eine ganze Kopie. Dies ist nützlich, wenn Sie das Ende des Bereichs mithilfe einer Variablen angeben und das letzte Element einschließen müssen.
Mark Ransom
6
Was mich wirklich nervt, ist, dass Python sagt, wenn Sie den Anfang und das Ende nicht festlegen, werden standardmäßig 0 und die Länge der Sequenz verwendet. Wenn Sie also "abcdef" [:: - 1] verwenden, sollte es theoretisch in "abcdef" [0: 6: -1] transformiert werden, aber diese beiden Ausdrücke erhalten nicht die gleiche Ausgabe. Ich habe das Gefühl, dass seit der Erstellung der Sprache etwas in der Python-Dokumentation fehlt.
Axell13
6
Und ich weiß, dass "abcdef" [:: - 1] in "abcdef" [6: -7: -1] umgewandelt wird. Der beste Weg, dies zu erklären, wäre: Sei len die Länge der Sequenz. Wenn der Schritt positiv ist , sind die Standardeinstellungen für Start und Ende 0 und len . Andernfalls, wenn Schritt negativ ist , sind die Standardeinstellungen für Start und Ende len und - len - 1.
axell13
4
Da stackoverflow.com/questions/39241529/… als dupe markiert ist, wäre es sinnvoll, einen Abschnitt mit delder Schriftart-Notation hinzuzufügen . Insbesondere del arr[:]ist nicht sofort offensichtlich ("arr [:] macht eine Kopie, löscht del diese Kopie ???" usw.)
khazhyk
538

Das Python-Tutorial spricht darüber (scrollen Sie ein wenig nach unten, bis Sie zu dem Teil über das Schneiden kommen).

Das ASCII-Grafikdiagramm ist auch hilfreich, um sich daran zu erinnern, wie Slices funktionieren:

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

Eine Möglichkeit, sich daran zu erinnern, wie Slices funktionieren, besteht darin, sich die Indizes so vorzustellen, dass sie zwischen Zeichen zeigen, wobei der linke Rand des ersten Zeichens mit 0 nummeriert ist. Dann hat der rechte Rand des letzten Zeichens einer Zeichenfolge mit n Zeichen den Index n .

Hans Nowak
quelle
10
Dieser Vorschlag funktioniert für einen positiven Schritt, aber nicht für einen negativen Schritt. Aus dem Diagramm erwarte ich a[-4,-6,-1], yPaber es ist ty. Was immer funktioniert, ist, in Zeichen oder Slots zu denken und die Indizierung als halboffenes Intervall zu verwenden - rechts offen, wenn positiver Schritt, links offen, wenn negativer Schritt.
Aguadopd
Es gibt jedoch keine Möglichkeit, ab dem Ende zu einem leeren Satz zusammenzufallen (wie x[:0]dies beim Anfang der Fall ist), sodass Sie kleine Arrays in Sonderfällen erstellen müssen. : /
Endolith
412

Aufzählung der Möglichkeiten der Grammatik:

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

Wenn ja (high-low)%stride != 0, dann ist der Endpunkt natürlich etwas niedriger als high-1.

Wenn stridenegativ, wird die Reihenfolge etwas geändert, da wir herunterzählen:

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

Erweitertes Slicing (mit Kommas und Ellipsen) wird meist nur von speziellen Datenstrukturen (wie NumPy) verwendet. Die Grundsequenzen unterstützen sie nicht.

>>> class slicee:
...     def __getitem__(self, item):
...         return repr(item)
...
>>> slicee()[0, 1:2, ::5, ...]
'(0, slice(1, 2, None), slice(None, None, 5), Ellipsis)'
kurzlebig
quelle
Eigentlich bleibt noch etwas aus, zB wenn ich 'apple' tippe [4: -4: -1] Ich bekomme 'elp', Python übersetzt die -4 vielleicht in eine 1?
Liyuan
Beachten Sie, dass Backticks zugunsten vonrepr
wjandrea
@liyuan Der Typ der Implementierung __getitem__ist; Ihr Beispiel entspricht apple[slice(4, -4, -1)].
Chepner
320

In den obigen Antworten wird die Slice-Zuweisung nicht erläutert. Um die Slice-Zuweisung zu verstehen, ist es hilfreich, der ASCII-Grafik ein weiteres Konzept hinzuzufügen:

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

Eine Heuristik ist, für ein Slice von Null bis n zu denken: "Null ist der Anfang, beginnen Sie am Anfang und nehmen Sie n Elemente in eine Liste".

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

Eine andere Heuristik lautet: "Ersetzen Sie für jedes Slice den Anfang durch Null, wenden Sie die vorherige Heuristik an, um das Ende der Liste zu erhalten, und zählen Sie dann die erste Zahl zurück, um Elemente vom Anfang zu entfernen."

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

Die erste Regel für die Slice-Zuweisung lautet, dass für die Slice-Zuweisung eine Liste (oder eine andere iterierbare) erforderlich ist, da das Slicing eine Liste zurückgibt :

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

Die zweite Regel der Slice-Zuweisung, die Sie auch oben sehen können, lautet, dass jeder Teil der Liste, der durch die Slice-Indizierung zurückgegeben wird, derselbe Teil ist, der durch die Slice-Zuweisung geändert wird:

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

Die dritte Regel für die Slice-Zuweisung lautet, dass die zugewiesene Liste (iterierbar) nicht dieselbe Länge haben muss. Das indizierte Slice wird einfach herausgeschnitten und massenhaft durch das ersetzt, was zugewiesen wird:

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

Der schwierigste Teil, an den man sich gewöhnen muss, ist die Zuordnung zu leeren Scheiben. Mit Heuristik 1 und 2 können Sie ganz einfach ein leeres Slice indizieren :

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

Und wenn Sie das gesehen haben, ist auch die Slice-Zuordnung zum leeren Slice sinnvoll:

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

Da wir die zweite Nummer des Slice (4) nicht ändern, stapeln sich die eingefügten Elemente immer direkt gegen das 'o', selbst wenn wir dem leeren Slice zuweisen. Die Position für die Zuweisung leerer Slices ist also die logische Erweiterung der Positionen für die Zuweisungen nicht leerer Slices.

Was passiert, wenn Sie mit unserer Prozession fortfahren, den Beginn der Scheibe hochzuzählen?

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

Wenn Sie mit dem Schneiden fertig sind, sind Sie fertig. es beginnt nicht rückwärts zu schneiden. In Python erhalten Sie keine negativen Schritte, es sei denn, Sie fragen explizit nach ihnen, indem Sie eine negative Zahl verwenden.

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

Die Regel "Sobald Sie fertig sind, sind Sie fertig" hat einige seltsame Konsequenzen:

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

Tatsächlich ist Python-Slicing im Vergleich zur Indizierung bizarr fehlersicher:

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

Dies kann manchmal nützlich sein, aber auch zu etwas seltsamem Verhalten führen:

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

Abhängig von Ihrer Anwendung könnte das ... oder auch nicht ... das sein, was Sie sich dort erhofft haben!


Unten ist der Text meiner ursprünglichen Antwort. Es war für viele Leute nützlich, deshalb wollte ich es nicht löschen.

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

Dies kann auch den Unterschied zwischen Schneiden und Indizieren verdeutlichen.

David M. Perlman
quelle
246

Erklären Sie Pythons Slice-Notation

Kurz gesagt, die Doppelpunkte ( :) in der Index - Notation ( subscriptable[subscriptarg]) make Slice - Notation - , die die optionalen Argumente haben, start, stop, step:

sliceable[start:stop:step]

Python Slicing ist eine rechnerisch schnelle Methode, um methodisch auf Teile Ihrer Daten zuzugreifen. Meiner Meinung nach ist es ein Aspekt der Sprache, mit dem man vertraut sein muss, um selbst ein fortgeschrittener Python-Programmierer zu sein.

Wichtige Definitionen

Lassen Sie uns zunächst einige Begriffe definieren:

start: Der Anfangsindex des Slice enthält das Element an diesem Index, sofern es nicht mit stop identisch ist. Der Standardwert ist 0, dh der erste Index. Wenn es negativ ist, bedeutet dies, dass die nElemente am Ende beginnen.

stop: Der Endindex des Slice enthält nicht das Element an diesem Index. Die Standardeinstellung ist die Länge der geschnittenen Sequenz, dh bis einschließlich des Endes.

Schritt: Der Betrag, um den der Index erhöht wird, ist standardmäßig 1. Wenn er negativ ist, schneiden Sie in umgekehrter Reihenfolge über das Iterable.

So funktioniert die Indizierung

Sie können jede dieser positiven oder negativen Zahlen eingeben. Die Bedeutung der positiven Zahlen ist unkompliziert, aber für negative Zahlen zählen Sie wie für Indizes in Python vom Ende an für Start und Stopp rückwärts und für den Schritt dekrementieren Sie einfach Ihren Index. Dieses Beispiel stammt aus dem Tutorial der Dokumentation , aber ich habe es leicht geändert, um anzugeben, auf welches Element in einer Sequenz jeder Index verweist:

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

Wie das Schneiden funktioniert

Um die Slice-Notation mit einer Sequenz zu verwenden, die dies unterstützt, müssen Sie mindestens einen Doppelpunkt in die eckigen Klammern setzen, die der Sequenz folgen (die die Methode der Sequenz gemäß dem Python-Datenmodell tatsächlich implementieren__getitem__ ).

Die Slice-Notation funktioniert folgendermaßen:

sequence[start:stop:step]

Und denken Sie daran, dass es Standardeinstellungen für Start , Stopp und Schritt gibt. Um auf die Standardeinstellungen zuzugreifen, lassen Sie das Argument einfach weg.

Die Slice-Notation zum Abrufen der letzten neun Elemente aus einer Liste (oder einer anderen Sequenz, die dies unterstützt, z. B. eine Zeichenfolge) sieht folgendermaßen aus:

my_list[-9:]

Wenn ich das sehe, lese ich den Teil in den Klammern als "9. vom Ende bis zum Ende". (Eigentlich verkürze ich es mental als "-9, on")

Erläuterung:

Die vollständige Notation ist

my_list[-9:None:None]

und um die Standardeinstellungen zu ersetzen (tatsächlich, wenn sie stepnegativ sind, ist stopdie Standardeinstellung -len(my_list) - 1, also Nonebedeutet Stop wirklich nur, dass es zu dem Endschritt geht, zu dem es führt):

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

Der Doppelpunkt , :ist, was Python sagt Sie , ihm ein Stück und nicht einen regulären Index sind zu geben. Aus diesem Grund ist die idiomatische Art, eine flache Kopie von Listen in Python 2 zu erstellen, die folgende

list_copy = sequence[:]

Und sie zu löschen ist mit:

del my_list[:]

(Python 3 erhält eine list.copyund list.clearMethode.)

Wenn stepnegativ ist, ändern sich die Standardeinstellungen startund stopändern sich

Wenn das stepArgument leer (oder None) ist, wird es standardmäßig zugewiesen +1.

Sie können jedoch eine negative Ganzzahl übergeben, und die Liste (oder die meisten anderen Standard-Slicables) wird vom Ende bis zum Anfang aufgeteilt.

Somit ändert ein negativer Slice die Standardeinstellungen für startundstop !

Bestätigen Sie dies in der Quelle

Ich möchte Benutzer dazu ermutigen, sowohl die Quelle als auch die Dokumentation zu lesen. Den Quellcode für Slice-Objekte und diese Logik finden Sie hier . Zuerst bestimmen wir, ob stepnegativ ist:

 step_is_negative = step_sign < 0;

Wenn ja, bedeutet die Untergrenze, -1 dass wir bis zum Anfang schneiden, und die Obergrenze ist die Länge minus 1, was bedeutet, dass wir am Ende beginnen. (Beachten Sie, dass die Semantik dies -1ist unterschiedlich von einem , -1dass die Benutzer - Indizes in Python passieren kann das letzte Element angezeigt wird .)

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

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

Andernfalls stepist es positiv, und die Untergrenze ist Null und die Obergrenze (bis zu der wir gehen, aber nicht einschließen) die Länge der geschnittenen Liste.

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

Dann müssen wir möglicherweise die Standardeinstellungen für startund anwenden stop- der Standardwert für startwird dann als Obergrenze berechnet, wenn er stepnegativ ist:

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

und stopdie Untergrenze:

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

Geben Sie Ihren Scheiben einen beschreibenden Namen!

Es kann nützlich sein, das Slice von der Übergabe an die list.__getitem__Methode zu trennen ( genau das tun die eckigen Klammern ). Selbst wenn Sie nicht neu darin sind, bleibt Ihr Code besser lesbar, sodass andere, die Ihren Code möglicherweise lesen müssen, besser verstehen können, was Sie tun.

Sie können einer Variablen jedoch nicht einfach einige durch Doppelpunkte getrennte Ganzzahlen zuweisen. Sie müssen das Slice-Objekt verwenden:

last_nine_slice = slice(-9, None)

Das zweite Argument Noneist erforderlich, damit das erste Argument als startArgument interpretiert wird, andernfalls wäre es das stopArgument .

Sie können das Slice-Objekt dann an Ihre Sequenz übergeben:

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

Es ist interessant, dass Bereiche auch Scheiben nehmen:

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

Überlegungen zum Speicher:

Da Scheiben Python - Listen neue Objekte im Speicher zu erstellen, in einer anderen wichtige Funktion bewusst ist , zu sein itertools.islice. Normalerweise möchten Sie über ein Slice iterieren und es nicht nur statisch im Speicher erstellen lassen. isliceist perfekt dafür. Ein Vorbehalt, es unterstützt nicht die negativen Argumente start, stopoder step, also , wenn das ein Problem ist Sie benötigen Indizes berechnen oder den iterable im Voraus zu umkehren.

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

und nun:

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

Die Tatsache, dass Listen-Slices eine Kopie erstellen, ist ein Merkmal der Listen selbst. Wenn Sie erweiterte Objekte wie einen Pandas DataFrame in Scheiben schneiden, wird möglicherweise eine Ansicht des Originals und keine Kopie zurückgegeben.

Aaron Hall
quelle
146

Und ein paar Dinge, die mir nicht sofort klar waren, als ich die Slicing-Syntax zum ersten Mal sah:

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

Einfache Möglichkeit, Sequenzen umzukehren!

Und wenn Sie aus irgendeinem Grund jeden zweiten Punkt in umgekehrter Reihenfolge wollten:

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

In Python 2.7

In Python schneiden

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

Das Verständnis der Indexzuweisung ist sehr wichtig.

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

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

Wenn Sie [a: b: c] sagen, sagen Sie abhängig vom Vorzeichen von c (vorwärts oder rückwärts), beginnen Sie bei a und enden Sie bei b (ohne Element am b-ten Index). Verwenden Sie die obige Indizierungsregel und denken Sie daran, dass Sie nur Elemente in diesem Bereich finden:

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

Dieser Bereich setzt sich jedoch unendlich in beide Richtungen fort:

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

Zum Beispiel:

             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

Wenn Ihre Auswahl von a, b und c eine Überlappung mit dem obigen Bereich beim Durchlaufen unter Verwendung der Regeln für a, b, c oben zulässt, erhalten Sie entweder eine Liste mit Elementen (die während des Durchlaufs berührt werden) oder eine leere Liste.

Eine letzte Sache: Wenn a und b gleich sind, erhalten Sie auch eine leere Liste:

>>> l1
[2, 3, 4]

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

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

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

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

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

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


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

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


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


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


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

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

>>> l1[:-2:-2] # a default is -1, stop(b) at -2 , step(c) by 2 in reverse direction
[4]
Ankur Agarwal
quelle
2
ein weiteres interessantes Beispiel: a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]; a[:-2:-2]was zu[9]
Deviacium
96

Ich habe diese großartige Tabelle unter http://wiki.python.org/moin/MovingToPythonFromOtherLanguages ​​gefunden

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

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

Nachdem ich es ein wenig benutzt habe, stelle ich fest, dass die einfachste Beschreibung ist, dass es genau das gleiche ist wie die Argumente in einer forSchleife ...

(from:to:step)

Alle sind optional:

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

Für die negative Indizierung müssen Sie nur die Länge der Zeichenfolge zu den negativen Indizes hinzufügen, um sie zu verstehen.

Das funktioniert sowieso bei mir ...

Simon
quelle
52

Es fällt mir leichter, mich daran zu erinnern, wie es funktioniert, und dann kann ich eine bestimmte Kombination aus Start, Stopp und Schritt herausfinden.

Es ist lehrreich, range()zuerst zu verstehen :

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

Beginnen Sie mit start, erhöhen Sie um step, erreichen Sie nicht stop. Sehr einfach.

Die Sache, an die man sich beim negativen Schritt erinnern sollte, ist, dass stopimmer das ausgeschlossene Ende ist, egal ob es höher oder niedriger ist. Wenn Sie dasselbe Slice in umgekehrter Reihenfolge möchten, ist es viel sauberer, die Umkehrung separat durchzuführen: z. B. 'abcde'[1:-2][::-1]schneidet ein Zeichen von links, zwei von rechts ab und kehrt dann um. (Siehe auch reversed().)

Das Sequenz-Slicing ist dasselbe, außer dass es zuerst negative Indizes normalisiert und niemals außerhalb der Sequenz liegen kann:

TODO : Der folgende Code hatte einen Fehler mit "nie außerhalb der Sequenz gehen", wenn abs (Schritt)> 1; Ich glaube, ich habe es gepatcht, um es richtig zu machen, aber es ist schwer zu verstehen.

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]

Machen Sie sich keine Sorgen um die is NoneDetails - denken Sie daran, dass das Weglassen startund / oder stopimmer das Richtige tut, um Ihnen die gesamte Sequenz zu geben.

Wenn Sie zuerst die negativen Indizes normalisieren, können Start und / oder Stopp unabhängig vom Ende gezählt werden: 'abcde'[1:-2] == 'abcde'[1:3] == 'bc'trotz range(1,-2) == []. Die Normalisierung wird manchmal als "Modulo der Länge" angesehen, aber beachten Sie, dass die Länge nur einmal hinzugefügt 'abcde'[-53:42]wird : zB ist nur die gesamte Zeichenfolge.

Beni Cherniavsky-Paskin
quelle
3
Das this_is_how_slicing_worksist nicht dasselbe wie Python Slice. EG [0, 1, 2][-5:3:3]wird [0] in Python erhalten, aber list(this_is_how_slicing_works([0, 1, 2], -5, 3, 3))[1].
Eastsun
@ Eastsun Ups, du hast recht! Ein klarerer Fall: range(4)[-200:200:3] == [0, 3]aber list(this_is_how_slicing_works([0, 1, 2, 3], -200, 200, 3)) == [2]. Mein if 0 <= i < len(seq):Versuch war, "nie außerhalb der Sequenz gehen" einfach zu implementieren, ist aber für Schritt> 1 falsch. Ich werde es später heute umschreiben (mit Tests).
Beni Cherniavsky-Paskin
40

Ich benutze die Methode "Ein Index zeigt zwischen Elementen", um selbst darüber nachzudenken, aber eine Art, es zu beschreiben, die manchmal anderen hilft, es zu bekommen, ist folgende:

mylist[X:Y]

X ist der Index des ersten gewünschten Elements.
Y ist der Index des ersten Elements, das Sie nicht möchten.

Steve Losh
quelle
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   :
|--------------->
    <---------------|

Ich hoffe, dies wird Ihnen helfen, die Liste in Python zu modellieren.

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

Xiaoyu
quelle
38

Python-Slicing-Notation:

a[start:end:step]
  • Für startund endwerden negative Werte als relativ zum Ende der Sequenz interpretiert.
  • Positive Indizes für endgeben die Position danach an dem letzten Element an, das aufgenommen werden soll.
  • Leerwerte werden standardmäßig wie folgt verwendet : [+0:-0:1].
  • Die Verwendung eines negativen Schritts kehrt die Interpretation von startund umend

Die Notation erstreckt sich auf (numpy) Matrizen und mehrdimensionale Arrays. Zum Schneiden ganzer Spalten können Sie beispielsweise Folgendes verwenden:

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

Slices enthalten Verweise und keine Kopien der Array-Elemente. Wenn Sie eine separate Kopie eines Arrays erstellen möchten, können Sie diese verwenden deepcopy().

kein Balken
quelle
34

Sie können auch die Slice-Zuweisung verwenden, um ein oder mehrere Elemente aus einer Liste zu entfernen:

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

Dies ist nur für einige zusätzliche Informationen ... Betrachten Sie die Liste unten

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

Einige andere Tricks zum Umkehren der Liste:

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

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

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

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

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

So bringe ich Neulingen Scheiben bei:

Den Unterschied zwischen Indizieren und Schneiden verstehen:

Wiki Python hat dieses erstaunliche Bild, das Indizierung und Slicing klar unterscheidet.

Geben Sie hier die Bildbeschreibung ein

Es ist eine Liste mit sechs Elementen. Um das Schneiden besser zu verstehen, betrachten Sie diese Liste als einen Satz von sechs Feldern, die zusammen angeordnet sind. Jede Box enthält ein Alphabet.

Die Indizierung ist wie der Umgang mit dem Inhalt der Box. Sie können den Inhalt eines beliebigen Kästchens überprüfen. Sie können jedoch nicht den Inhalt mehrerer Kästchen gleichzeitig überprüfen. Sie können sogar den Inhalt der Box ersetzen. Sie können jedoch nicht zwei Bälle in eine Schachtel legen oder zwei Bälle gleichzeitig ersetzen.

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

Das Schneiden ist wie der Umgang mit Kisten selbst. Sie können die erste Schachtel aufheben und auf einen anderen Tisch stellen. Um die Box aufzunehmen, müssen Sie lediglich die Position von Anfang und Ende der Box kennen.

Sie können sogar die ersten drei Felder oder die letzten beiden Felder oder alle Felder zwischen 1 und 4 auswählen. Sie können also einen beliebigen Satz von Feldern auswählen, wenn Sie den Anfang und das Ende kennen. Diese Positionen werden als Start- und Stopppositionen bezeichnet.

Das Interessante ist, dass Sie mehrere Boxen gleichzeitig ersetzen können. Sie können auch mehrere Felder platzieren, wo immer Sie möchten.

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

Schneiden mit Schritt:

Bis jetzt haben Sie fortlaufend Kisten gepflückt. Aber manchmal müssen Sie diskret abholen. Zum Beispiel können Sie jede zweite Box abholen. Sie können sogar jede dritte Kiste am Ende abholen. Dieser Wert wird als Schrittgröße bezeichnet. Dies stellt die Lücke zwischen Ihren aufeinanderfolgenden Tonabnehmern dar. Die Schrittgröße sollte positiv sein, wenn Sie Kästchen von Anfang bis Ende auswählen und umgekehrt.

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

Wie Python fehlende Parameter herausfindet:

Wenn Sie beim Schneiden einen Parameter weglassen, versucht Python, ihn automatisch herauszufinden.

Wenn Sie den Quellcode von CPython überprüfen , finden Sie eine Funktion namens PySlice_GetIndicesEx (), die Indizes für ein Slice für bestimmte Parameter ermittelt. Hier ist der logisch äquivalente Code in Python.

Diese Funktion verwendet ein Python-Objekt und optionale Parameter für das Slicing und gibt die Start-, Stopp-, Schritt- und Slice-Länge für das angeforderte Slice zurück.

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)

Dies ist die Intelligenz, die hinter Scheiben vorhanden ist. Da Python über eine integrierte Funktion namens Slice verfügt, können Sie einige Parameter übergeben und überprüfen, wie intelligent fehlende Parameter berechnet werden.

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]

Hinweis: Dieser Beitrag wurde ursprünglich in meinem Blog The Intelligence Behind Python Slices geschrieben .

ChillarAnand
quelle
29

In der Regel führt das Schreiben von Code mit vielen fest codierten Indexwerten zu Lesbarkeits- und Wartungsproblemen. Wenn Sie beispielsweise ein Jahr später auf den Code zurückkommen, werden Sie ihn sich ansehen und sich fragen, was Sie gedacht haben, als Sie ihn geschrieben haben. Die gezeigte Lösung ist lediglich eine Möglichkeit, klarer anzugeben, was Ihr Code tatsächlich tut. Im Allgemeinen erstellt das integrierte Slice () ein Slice-Objekt, das überall dort verwendet werden kann, wo ein Slice zulässig ist. Zum Beispiel:

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

Wenn Sie eine Slice-Instanz haben, können Sie weitere Informationen dazu erhalten, indem Sie sich die Attribute s.start, s.stop und s.step ansehen. Zum Beispiel:

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

1. Slice-Notation

Denken Sie zur Vereinfachung daran, dass Slice nur eine Form hat:

s[start:end:step]

und so funktioniert es:

  • s: ein Objekt, das in Scheiben geschnitten werden kann
  • start: Erster Index zum Starten der Iteration
  • end: letzter Index, HINWEIS: Der endIndex wird nicht in das resultierende Slice aufgenommen
  • step: wähle jedes stepIndexelement aus

Eine weitere Import Sache: alle start, end, stepkann verzichtet werden! Und wenn sie nicht angegeben werden, wird ihr Standardwert verwendet werden: 0, len(s),1 entsprechend.

Mögliche Variationen sind also:

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

HINWEIS: Wenn start >= end(nur wenn step>0), gibt Python ein leeres Slice zurück[] .

2. Fallstricke

Im obigen Teil werden die Hauptfunktionen für die Funktionsweise von Slice erläutert, die in den meisten Fällen funktionieren. Es kann jedoch Fallstricke geben, auf die Sie achten sollten, und dieser Teil erklärt sie.

Negative Indizes

Das allererste, was Python-Lernende verwirrt, ist, dass ein Index negativ sein kann! Keine Panik: Ein negativer Index bedeutet, rückwärts zu zählen.

Zum Beispiel:

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

Negativer Schritt

Die Dinge verwirrender zu machen ist, dass stepdas auch negativ sein kann!

Ein negativer Schritt bedeutet, dass das Array rückwärts iteriert wird: vom Ende bis zum Start, wobei der Endindex enthalten ist und der Startindex vom Ergebnis ausgeschlossen ist.

HINWEIS : wenn der Schritt negativ ist , ist der Standardwert für startist len(s)(während endnicht gleich ist 0, weil s[::-1]enthält s[0]). Zum Beispiel:

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

Fehler außerhalb des Bereichs?

Seien Sie überrascht: Slice löst keinen IndexError aus, wenn der Index außerhalb des Bereichs liegt!

Wenn der Index außerhalb des Bereichs liegt, versucht Python nach besten Kräften, den Index auf 0oder len(s)entsprechend der Situation festzulegen. Zum Beispiel:

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

Lassen Sie uns diese Antwort mit Beispielen beenden und alles erklären, was wir besprochen haben:

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

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

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

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

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

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

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

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

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

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

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

In [14]: s[5:1]    # Start > end; return empty list
Out[14]: []

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

IndexError: list index out of range
Cizixs
quelle
24

In den vorherigen Antworten wird nicht auf mehrdimensionales Array-Slicing eingegangen, das mit dem berühmten NumPy- Paket möglich ist:

Das Schneiden kann auch auf mehrdimensionale Arrays angewendet werden.

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

Das " :2" vor dem Komma wirkt auf die erste Dimension und das " 0:3:2" nach dem Komma auf die zweite Dimension.

Statham
quelle
4
Nur eine freundliche Erinnerung, dass Sie dies nicht auf Python tun können, listsondern nur auf arrayin Numpy
Mars Lee
15
#!/usr/bin/env python

def slicegraphical(s, lista):

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

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


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

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

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


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

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

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

    slicegraphical(s, lista)

Sie können dieses Skript ausführen und damit experimentieren. Nachfolgend finden Sie einige Beispiele, die ich aus dem Skript erhalten habe.

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

Beachten Sie bei Verwendung eines negativen Schritts, dass die Antwort um 1 nach rechts verschoben ist.

Mahmoh
quelle
14

Mein Gehirn scheint glücklich zu sein, zu akzeptieren, dass es lst[start:end]den start-ten Gegenstand enthält . Ich könnte sogar sagen, dass es eine "natürliche Annahme" ist.

Aber gelegentlich schleicht sich ein Zweifel ein und mein Gehirn bittet um Bestätigung, dass es nicht das end-te Element enthält.

In diesen Momenten verlasse ich mich auf diesen einfachen Satz:

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

Diese hübsche Eigenschaft sagt mir, dass lst[start:end]sie das end-te Element nicht enthält , weil es in istlst[end:] .

Beachten Sie, dass dieser Satz für nalle gilt. Sie können dies beispielsweise überprüfen

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

kehrt zurück True.

Robert
quelle
12

Meiner Meinung nach werden Sie die Python-String-Slicing-Notation besser verstehen und auswendig lernen, wenn Sie sie folgendermaßen betrachten (lesen Sie weiter).

Lassen Sie uns mit der folgenden Zeichenfolge arbeiten ...

azString = "abcdefghijklmnopqrstuvwxyz"

Für diejenigen, die es nicht wissen, können Sie azStringmithilfe der Notation einen beliebigen Teilstring erstellenazString[x:y]

Aus anderen Programmiersprachen kommend, wird der gesunde Menschenverstand beeinträchtigt. Was sind x und y?

Ich musste mich hinsetzen und verschiedene Szenarien ausführen, um eine Memorisierungstechnik zu finden, die mir hilft, mich an x ​​und y zu erinnern und beim ersten Versuch, Strings richtig zu schneiden.

Meine Schlussfolgerung ist, dass x und y als die Grenzindizes angesehen werden sollten, die die Zeichenfolgen umgeben, die wir hinzufügen möchten. Wir sollten den Ausdruck also als azString[index1, index2]oder noch deutlicher als sehenazString[index_of_first_character, index_after_the_last_character] .

Hier ist ein Beispiel für eine Visualisierung davon ...

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

Sie müssen also nur index1 und index2 auf die Werte setzen, die den gewünschten Teilstring umgeben. Um beispielsweise den Teilstring "cdefgh" abzurufen, können Sie ihn verwendenazString[2:8] , da der Index auf der linken Seite von "c" 2 und der auf der rechten Seite von "h" 8 ist.

Denken Sie daran, dass wir die Grenzen setzen. Und diese Grenzen sind die Positionen, an denen Sie einige Klammern platzieren können, die wie folgt um den Teilstring gewickelt werden ...

ab [ cdefgh ] ij

Dieser Trick funktioniert die ganze Zeit und ist leicht zu merken.

Asiby
quelle
11

Die meisten der vorherigen Antworten klären Fragen zur Slice-Notation.

Die erweiterte Indizierungssyntax für das Slicing lautet aList[start:stop:step]: Grundlegende Beispiele sind:

Geben Sie hier die Bildbeschreibung ein::

Weitere Schnittbeispiele: 15 Extended Slices

Roshan Bagdiya
quelle
10

In Python ist die grundlegendste Form zum Schneiden die folgende:

l[start:end]

Wo list eine Sammlung, startist ein inklusiver Index und endist ein exklusiver Index.

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]

Wenn Sie von Anfang an schneiden, können Sie den Nullindex weglassen, und wenn Sie bis zum Ende schneiden, können Sie den endgültigen Index weglassen, da er redundant ist. Seien Sie also nicht wortreich:

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

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

Negative Ganzzahlen sind nützlich, wenn Offsets relativ zum Ende einer Sammlung ausgeführt werden:

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]

Es ist möglich, Indizes bereitzustellen, die beim Schneiden außerhalb der Grenzen liegen, wie z.

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]

Denken Sie daran, dass das Ergebnis des Schneidens einer Sammlung eine völlig neue Sammlung ist. Wenn Sie die Slice-Notation in Zuweisungen verwenden, muss die Länge der Slice-Zuweisungen nicht gleich sein. Die Werte vor und nach dem zugewiesenen Slice werden beibehalten, und die Sammlung wird verkleinert oder vergrößert, um die neuen Werte zu enthalten:

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]

Wenn Sie den Start- und Endindex weglassen, erstellen Sie eine Kopie der Sammlung:

In [14]: l_copy = l[:]

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

Wenn die Start- und Endindizes beim Ausführen einer Zuweisungsoperation weggelassen werden, wird der gesamte Inhalt der Sammlung durch eine Kopie dessen ersetzt, worauf verwiesen wird:

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

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

Neben dem einfachen Schneiden ist es auch möglich, die folgende Notation anzuwenden:

l[start:end:step]

Wo list eine Sammlung, startist ein inklusiver Index, endist ein exklusiver Index und stepist ein Schritt, der verwendet werden kann, um jedes n-te Element aufzunehmen 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]

Die Verwendung stepbietet einen nützlichen Trick, um eine Sammlung in Python umzukehren:

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

Es ist auch möglich, negative Ganzzahlen für stepdas folgende Beispiel zu verwenden:

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

Die Verwendung eines negativen Werts für kann stepjedoch sehr verwirrend werden. Um darüber hinaus zu sein Pythonic , sollten Sie vermeiden , mit start, endund stepin einer einzigen Scheibe. Wenn dies erforderlich ist, sollten Sie dies in zwei Aufgaben tun (eine zum Schneiden und die andere zum Schritt).

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

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

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

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

Ich möchte eine hinzufügen Hallo, Welt! Beispiel, das die Grundlagen von Slices für Anfänger erklärt. Es hat mir sehr geholfen.

Lassen Sie uns eine Liste mit sechs Werten haben ['P', 'Y', 'T', 'H', 'O', 'N']:

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

Die einfachsten Abschnitte dieser Liste sind die Unterlisten. Die Notation ist [<index>:<index>]und der Schlüssel ist, es so zu lesen:

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

Wenn Sie nun einen Ausschnitt [2:5]aus der obigen Liste erstellen, geschieht Folgendes:

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

Sie haben einen Schnitt vor dem Element mit dem Index 2und einem anderen Schnitt vor dem Element mit dem Index 5. Das Ergebnis ist also ein Schnitt zwischen diesen beiden Schnitten, eine Liste ['T', 'H', 'O'].

Jeyekomon
quelle
10

Ich persönlich denke darüber nach wie eine forSchleife:

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

Beachten Sie außerdem, dass negative Werte für startund endrelativ zum Ende der Liste sind und im obigen Beispiel von berechnet wurden given_index + a.shape[0].

Raman
quelle
8

Das Folgende ist das Beispiel eines Index einer Zeichenfolge:

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

str="Name string"

Schnittbeispiel: [Start: Ende: Schritt]

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

Unten ist die Beispielverwendung:

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
Prinz Dhadwal
quelle
5

Wenn Sie der Meinung sind, dass negative Indizes beim Schneiden verwirrend sind, können Sie dies ganz einfach in Betracht ziehen: Ersetzen Sie einfach den negativen Index durch len - index. Ersetzen Sie beispielsweise -3 durch len(list) - 3.

Der beste Weg, um zu veranschaulichen, was das Schneiden intern tut, besteht darin, es nur in Code zu zeigen, der diese Operation implementiert:

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

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

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

Die grundlegende Schneidetechnik besteht darin, den Startpunkt, den Haltepunkt und die Schrittgröße zu definieren - auch als Schritt bezeichnet.

Zuerst erstellen wir eine Liste von Werten, die in unserem Slicing verwendet werden sollen.

Erstellen Sie zwei Listen zum Schneiden. Die erste ist eine numerische Liste von 1 bis 9 (Liste A). Die zweite ist ebenfalls eine numerische Liste von 0 bis 9 (Liste 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)

Indexieren Sie die Nummer 3 von A und die Nummer 6 von B.

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

Grundlegendes Schneiden

Die erweiterte Indexierungssyntax für das Slicing lautet aList [start: stop: step]. Das Startargument und das Schrittargument sind standardmäßig keine - das einzige erforderliche Argument ist stop. Haben Sie bemerkt, dass dies ähnlich ist, wie der Bereich zum Definieren der Listen A und B verwendet wurde? Dies liegt daran, dass das Slice-Objekt den Satzbereich darstellt, der durch den Bereich (Start, Stopp, Schritt) angegeben wird. Python 3.4-Dokumentation.

Wie Sie sehen können, gibt das Definieren nur von stop ein Element zurück. Da der Start standardmäßig "none" ist, wird nur ein Element abgerufen.

Es ist wichtig zu beachten, dass das erste Element der Index 0 ist, nicht Index 1 ist. Aus diesem Grund verwenden wir für diese Übung zwei Listen. Die Elemente von Liste A werden gemäß der Ordnungsposition nummeriert (das erste Element ist 1, das zweite Element ist 2 usw.), während die Elemente von Liste B die Zahlen sind, die verwendet werden würden, um sie zu indizieren ([0] für das erste Element 0, usw.).

Mit der erweiterten Indizierungssyntax rufen wir einen Wertebereich ab. Beispielsweise werden alle Werte mit einem Doppelpunkt abgerufen.

A[:]

Um eine Teilmenge von Elementen abzurufen, müssen die Start- und Stopppositionen definiert werden.

Rufen Sie unter Berücksichtigung des Musters aList [start: stop] die ersten beiden Elemente aus Liste A ab.

Babu Chandermani
quelle
3

Ich denke nicht, dass das Python-Tutorial- Diagramm (in verschiedenen anderen Antworten zitiert) gut ist, da dieser Vorschlag für positive Schritte funktioniert, aber nicht für negative Schritte.

Dies ist das Diagramm:

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

Aus dem Diagramm erwarte ich a[-4,-6,-1], yPaber es ist ty.

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

Was immer funktioniert, ist, in Zeichen oder Slots zu denken und die Indizierung als halboffenes Intervall zu verwenden - rechts offen, wenn positiver Schritt, links offen, wenn negativer Schritt.

Auf diese Weise kann ich mir a[-4:-6:-1]wie a(-6,-4]in der Intervallterminologie vorstellen.

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

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