operator - Entendiendo la notación de corte de Python
slicing en python (30)
Necesito una buena explicación (las referencias son una ventaja) en la notación de corte de Python.
Para mí, esta notación necesita un poco de recuperación.
Parece extremadamente poderoso, pero no he logrado entenderlo.
Explique la notación de corte de Python.
En resumen, los dos puntos (:) en la notación de subíndices ( subscriptable[subscriptarg]
) hacen notación de segmento, que tiene los argumentos opcionales, start
, stop
, step
:
sliceable[start:stop:step]
El corte de Python es una forma computacionalmente rápida de acceder metódicamente a partes de sus datos. En mi opinión, para ser incluso un programador de Python intermedio, es un aspecto del lenguaje con el que es necesario estar familiarizado.
Definiciones importantes
Para empezar, definamos algunos términos:
inicio: el índice de inicio de la división, incluirá el elemento en este índice a menos que sea el mismo que detener , el valor predeterminado es 0, es decir, el primer índice. Si es negativo, significa iniciar
n
elementos desde el final.detener: el índice final de la división, no incluye el elemento en este índice, la longitud predeterminada de la secuencia se divide, es decir, hasta e incluyendo el final.
paso: la cantidad en la que aumenta el índice, el valor predeterminado es 1. Si es negativo, está rebanando lo iterable a la inversa.
Cómo funciona la indexación
Puedes hacer cualquiera de estos números positivos o negativos. El significado de los números positivos es sencillo, pero para los números negativos, al igual que los índices en Python, contamos hacia atrás desde el final para el inicio y el final , y para el paso , simplemente disminuimos el índice. Este ejemplo es del tutorial de la documentación , pero lo he modificado ligeramente para indicar a qué elemento en una secuencia se refiere cada índice:
+---+---+---+---+---+---+
| P | y | t | h | o | n |
+---+---+---+---+---+---+
0 1 2 3 4 5
-6 -5 -4 -3 -2 -1
Cómo funciona el rebanado
Para usar la notación de división con una secuencia que lo admita, debe incluir al menos un signo de dos puntos entre los corchetes que siguen la secuencia (que implementa el método __getitem__
de la secuencia, de acuerdo con el modelo de datos de Python ).
La notación de la rebanada funciona así:
sequence[start:stop:step]
Y recuerde que hay valores predeterminados para inicio , parada y paso , por lo que para acceder a los valores predeterminados, simplemente omita el argumento.
La notación de división para obtener los últimos nueve elementos de una lista (o cualquier otra secuencia que la admita, como una cadena) se vería así:
my_list[-9:]
Cuando veo esto, leo la parte entre corchetes como "9 desde el final, hasta el final". (En realidad, lo abrevio mentalmente como "-9, en")
Explicación:
La notación completa es
my_list[-9:None:None]
y para sustituir los valores predeterminados (en realidad, cuando el step
es negativo, el valor predeterminado de -len(my_list) - 1
es -len(my_list) - 1
, por lo que None
para detener realmente significa que va a cualquier paso final que lo lleve a):
my_list[-9:len(my_list):1]
Los dos puntos , :
, es lo que le dice a Python que le está dando una porción y no un índice regular. Es por eso que la forma idiomática de hacer una copia superficial de las listas en Python 2 es
list_copy = sequence[:]
Y limpiarlos es con:
del my_list[:]
(Python 3 obtiene un método list.copy
y list.clear
).
Cuando el step
es negativo, los valores predeterminados de start
y stop
cambian
De forma predeterminada, cuando el argumento de step
está vacío (o None
), se asigna a +1
.
Sin embargo, puede pasar un entero negativo, y la lista (o la mayoría de los otros elementos seleccionables estándar) se dividirá desde el final hasta el principio.
Por lo tanto, un segmento negativo cambiará los valores predeterminados para start
y stop
.
Confirmando esto en la fuente.
Me gusta animar a los usuarios a leer la fuente, así como la documentación. El código fuente de los objetos de división y esta lógica se encuentran aquí . Primero determinamos si el step
es negativo:
step_is_negative = step_sign < 0;
Si es así, el límite inferior es -1
lo que significa que cortamos todo el camino hasta e incluyendo el comienzo, y el límite superior es la longitud menos 1, lo que significa que comenzamos por el final. (Tenga en cuenta que la semántica de este -1
es diferente de un -1
que los usuarios pueden pasar índices en Python que indican el último elemento).
if (step_is_negative) { lower = PyLong_FromLong(-1L); if (lower == NULL) goto error; upper = PyNumber_Add(length, lower); if (upper == NULL) goto error; }
De lo contrario, el step
es positivo, y el límite inferior será cero y el límite superior (que vamos hasta pero sin incluir) la longitud de la lista dividida.
else { lower = _PyLong_Zero; Py_INCREF(lower); upper = length; Py_INCREF(upper); }
Entonces, es posible que tengamos que aplicar los valores predeterminados para el start
y la stop
; el valor predeterminado para el start
se calcula como el límite superior cuando el step
es negativo:
if (self->start == Py_None) { start = step_is_negative ? upper : lower; Py_INCREF(start); }
y stop
, el límite inferior:
if (self->stop == Py_None) { stop = step_is_negative ? lower : upper; Py_INCREF(stop); }
¡Dale a tus cortes un nombre descriptivo!
Puede que le resulte útil separar la formación de la porción de pasarla a la list.__getitem__
método list.__getitem__
( eso es lo que hacen los corchetes ). Incluso si no es nuevo en esto, mantiene su código más legible para que otros que tengan que leer su código puedan entender más fácilmente lo que está haciendo.
Sin embargo, no puede simplemente asignar algunos enteros separados por dos puntos a una variable. Necesitas usar el objeto slice:
last_nine_slice = slice(-9, None)
El segundo argumento, None
, es obligatorio, de modo que el primer argumento se interpreta como el argumento de start
contrario sería el argumento de stop
.
A continuación, puede pasar el objeto de división a su secuencia:
>>> list(range(100))[last_nine_slice]
[91, 92, 93, 94, 95, 96, 97, 98, 99]
Es interesante que los rangos también toman rebanadas:
>>> range(100)[last_nine_slice]
range(91, 100)
Consideraciones de memoria:
Dado que los segmentos de las listas de Python crean nuevos objetos en la memoria, otra función importante a tener en cuenta es itertools.islice
. Por lo general, querrá iterar sobre un segmento, no solo tenerlo creado estáticamente en la memoria. islice
es perfecto para esto. Una advertencia, no admite argumentos negativos para start
, stop
o step
, por lo que si ese es un problema, es posible que necesite calcular índices o revertir el iterable por adelantado.
length = 100
last_nine_iter = itertools.islice(list(range(length)), length-9, None, 1)
list_last_nine = list(last_nine_iter)
y ahora:
>>> list_last_nine
[91, 92, 93, 94, 95, 96, 97, 98, 99]
El hecho de que las porciones de la lista hagan una copia es una característica de las listas. Si está cortando objetos avanzados como Pandas DataFrame, puede devolver una vista en el original, y no una copia.
1. Notación de la rebanada
Para hacerlo simple, recuerde que la sección tiene solo una forma :
s[start:end:step]
Y así es como funciona:
-
s
: un objeto que puede ser cortado -
start
: primer índice para iniciar la iteración -
end
: último índice, NOTA que el índiceend
no se incluirá en la porción resultante -
step
: elegir elemento cada índice destep
Otra cosa importante: todo start
, end
, step
puede ser omitido! Y si se omiten, se utilizará su valor predeterminado: 0
, len(s)
, 1
consecuencia.
Así que las posibles variaciones son:
# 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: Si start>=end
(considerando solo cuando step>0
), python devolverá una división vacía []
.
2. Escollos
La parte anterior explica las funciones principales sobre cómo funciona la división, funcionará en la mayoría de las ocasiones. Sin embargo, puede haber problemas que debe tener en cuenta, y esta parte los explica.
Índices negativos
¡Lo primero que confunde a los aprendices de Python es que el índice puede ser negativo! No se asuste: el índice negativo significa contar desde atrás.
Por ejemplo:
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]
Paso negativo
Hacer las cosas más confusas es que el step
puede ser negativo también!
Paso negativo significa iterar la matriz hacia atrás: desde el final hasta el inicio, con el índice final incluido y el índice de inicio excluido del resultado.
NOTA : cuando el paso es negativo, el valor predeterminado para start
a len(s)
(mientras que el end
no es igual a 0
, porque s[::-1]
contiene s[0]
). Por ejemplo:
s[::-1] # reversed slice
s[len(s)::-1] # same as above, reversed slice
s[0:len(s):-1] # empty list
¿Error fuera de rango?
¡ Sorpréndase: la división no eleva IndexError cuando el índice está fuera de rango!
Si el índice está fuera de rango, Python intentará de la mejor manera establecer el índice en 0
o len(s)
según la situación. Por ejemplo:
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. Ejemplos
Terminemos esta respuesta con ejemplos que explican todo lo que hemos discutido:
# 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
Así es como enseño las rebanadas a los novatos:
Entendiendo la diferencia entre indexación y corte:
Wiki Python tiene esta increíble imagen que distingue claramente la indexación y el corte.
Es una lista con 6 elementos en ella. Para comprender mejor cómo rebanar, considere esa lista como un conjunto de seis cuadros colocados juntos. Cada caja tiene un alfabeto en ella.
La indexación es como tratar con los contenidos de la caja. Puede consultar el contenido de cualquier casilla. Pero no puedes marcar el contenido de varias casillas a la vez. Incluso puede reemplazar el contenido de la caja. Pero no puede colocar 2 bolas en 1 caja o reemplazar 2 bolas a la vez.
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
Cortar es como tratar con cajas en sí. Puede recoger la primera caja y colocarla en otra mesa. Para recoger la caja, todo lo que necesita saber es la posición de inicio y finalización de la caja.
Incluso puede recoger las primeras 3 casillas o las 2 últimas casillas o todas las casillas entre 1 y 4. Por lo tanto, puede elegir cualquier conjunto de casillas si sabe el principio y el final. Estas posiciones se llaman posiciones de inicio y parada.
Lo interesante es que puedes reemplazar múltiples cajas a la vez. También puedes colocar múltiples cajas donde quieras.
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'']
Cortando Con Paso:
Hasta ahora has recogido cajas continuamente. Pero algunas veces hay que recoger discretamente. Por ejemplo, puede recoger cada segundo cuadro. Incluso puedes recoger cada tercer cuadro desde el final. Este valor se llama tamaño de paso. Esto representa la brecha entre sus recolecciones sucesivas. El tamaño del paso debe ser positivo si está seleccionando cuadros desde el principio hasta el final y 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]: []
Cómo Python descubre los parámetros que faltan:
Al rebanar si omite cualquier parámetro, Python intenta resolverlo automáticamente.
Si verifica el código fuente de CPython, encontrará una función llamada PySlice_GetIndicesEx que calcula los índices en una porción para cualquier parámetro dado. Aquí está el código equivalente lógico en Python.
Esta función toma un objeto Python y parámetros opcionales para segmentar y devuelve la longitud de inicio, parada, paso y segmentación para la división solicitada.
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)
Esta es la inteligencia que está presente detrás de las rebanadas. Como Python tiene una función incorporada llamada slice, puede pasar algunos parámetros y verificar qué tan inteligente calcula los parámetros faltantes.
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: esta publicación está originalmente escrita en mi blog http://www.avilpage.com/2015/03/a-slice-of-python-intelligence-behind.html
Como regla general, la escritura de código con muchos valores de índice codificados de forma rígida conduce a un problema de legibilidad y mantenimiento. Por ejemplo, si regresa al código un año después, lo verá y se preguntará qué pensaba cuando lo escribió. La solución mostrada es simplemente una forma de indicar más claramente lo que realmente está haciendo su código. En general, la división incorporada () crea un objeto de división que se puede utilizar en cualquier lugar donde se permita una división. Por ejemplo:
>>> 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]
Si tiene una instancia de división, puede obtener más información sobre ella mirando sus atributos s.start, s.stop y s.step, respectivamente. Por ejemplo:
>>> a = slice(10, 50, 2) >>> a.start 10 >>> a.stop 50 >>> a.step 2 >>>
Después de usarlo un poco, me doy cuenta de que la descripción más simple es que es exactamente lo mismo que los argumentos en un bucle for ...
(from:to:step)
cualquiera de ellos es opcional
(:to:step)
(from::step)
(from:to)
luego, la indexación negativa solo necesita que usted agregue la longitud de la cadena a los índices negativos para entenderla.
Esto funciona para mí de todos modos ...
El tutorial de Python habla sobre esto (desplácese hacia abajo un poco hasta que llegue a la parte sobre el corte).
El diagrama artístico ASCII también es útil para recordar cómo funcionan los cortes:
+---+---+---+---+---+---+
| P | y | t | h | o | n |
+---+---+---+---+---+---+
0 1 2 3 4 5 6
-6 -5 -4 -3 -2 -1
Una forma de recordar cómo funcionan los cortes es pensar que los índices apuntan entre los caracteres, con el borde izquierdo del primer carácter numerado 0. Luego, el borde derecho del último carácter de una cadena de n caracteres tiene un índice n .
En Python 2.7
Rebanar en 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).
Comprender la asignación de índice es muy importante.
In forward direction, starts at 0 and ends at len-1
In backward direction, starts at -1 and ends at -len
Cuando dice [a: b: c], está diciendo que dependiendo del signo de c (adelante o atrás), comience en a y termine en b (excluyendo el elemento en el bth index). Utilice la regla de indexación anterior y recuerde que solo encontrará elementos en este rango:
-len, -len+1, -len+2, ..., 0, 1, 2,3,4 , len -1
Pero este rango continúa infinitamente en ambas direcciones:
...,-len -2 ,-len-1,-len, -len+1, -len+2, ..., 0, 1, 2,3,4 , len -1, len, len +1, len+2 , ....
Por ejemplo:
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
Si su elección de a, b, y c permite superponerse con el rango anterior a medida que recorre las reglas para a, b, c anterior, obtendrá una lista con elementos (pulsados durante el recorrido) o obtendrá una lista vacía.
Una última cosa: si a y b son iguales, entonces también obtienes una lista vacía:
>>> 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]
Encontré esta gran tabla en http://wiki.python.org/moin/MovingToPythonFromOtherLanguages
Python indexes and slices for a six-element list.
Indexes enumerate the elements, slices enumerate the spaces between the elements.
Index from rear: -6 -5 -4 -3 -2 -1 a=[0,1,2,3,4,5] a[1:]==[1,2,3,4,5]
Index from front: 0 1 2 3 4 5 len(a)==6 a[:5]==[0,1,2,3,4]
+---+---+---+---+---+---+ a[0]==0 a[:-2]==[0,1,2,3]
| a | b | c | d | e | f | a[5]==5 a[1:2]==[1]
+---+---+---+---+---+---+ a[-1]==5 a[1:-1]==[1,2,3,4]
Slice from front: : 1 2 3 4 5 : a[-2]==4
Slice from rear: : -5 -4 -3 -2 -1 :
b=a[:]
b==[0,1,2,3,4,5] (shallow copy of a)
Enumerando las posibilidades permitidas por la gramática:
>>> 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]]
Por supuesto, si (high-low)%stride != 0
, el punto final será un poco más bajo que high-1
.
Si stride
es negativa, el orden se cambia un poco ya que estamos haciendo una cuenta regresiva:
>>> 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]]
El corte extendido (con comas y puntos suspensivos) se usa principalmente solo por estructuras de datos especiales (como Numpy); Las secuencias básicas no las soportan.
>>> class slicee:
... def __getitem__(self, item):
... return `item`
...
>>> slicee()[0, 1:2, ::5, ...]
''(0, slice(1, 2, None), slice(None, None, 5), Ellipsis)''
Es bastante simple en realidad:
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
También está el valor de step
, que se puede utilizar con cualquiera de los anteriores:
a[start:end:step] # start through not past end, by step
El punto clave a recordar es que :end
valor :end
representa el primer valor que no está en el sector seleccionado. Por lo tanto, la diferencia entre el end
y el start
es la cantidad de elementos seleccionados (si el step
es 1, el valor predeterminado).
La otra característica es que el start
o el end
puede ser un número negativo , lo que significa que cuenta desde el final de la matriz en lugar del principio. Asi que:
a[-1] # last item in the array
a[-2:] # last two items in the array
a[:-2] # everything except the last two items
Del mismo modo, el step
puede ser un número 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 es amable con el programador si hay menos elementos de los que pide. Por ejemplo, si solicita a[:-2]
y solo contiene un elemento, obtiene una lista vacía en lugar de un error. A veces, prefiere el error, por lo que debe tener en cuenta que esto puede suceder.
Esto es solo para información adicional ... Considere la lista a continuación
>>> l=[12,23,345,456,67,7,945,467]
Algunos otros trucos para revertir 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]
Vea la respuesta de abc arriba
Las respuestas anteriores no discuten la asignación de sectores. Para comprender la asignación de segmentos, es útil agregar otro concepto al arte ascii:
+---+---+---+---+---+---+
| P | y | t | h | o | n |
+---+---+---+---+---+---+
Slice position: 0 1 2 3 4 5 6
Index position: 0 1 2 3 4 5
>>> p = [''P'',''y'',''t'',''h'',''o'',''n'']
# Why the two sets of numbers:
# indexing gives items, not lists
>>> p[0]
''P''
>>> p[5]
''n''
# slicing gives lists
>>> p[0:1]
[''P'']
>>> p[0:2]
[''P'',''y'']
Una heurística es, para una porción de cero a n, piense: "cero es el comienzo, comience por el principio y tome n elementos en 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'']
Otra heurística es: "para cualquier sector, reemplace el inicio por cero, aplique el método anterior para obtener el final de la lista, luego cuente el primer número para recortar los elementos del principio"
>>> 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 primera regla de la asignación de división es que, dado que la segmentación devuelve una lista, la asignación de división requiere una lista (u otro iterable):
>>> 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 segunda regla de la asignación de segmentos, que también puede ver arriba, es que cualquier parte de la lista se devuelve mediante la indexación de segmentos, que es la misma porción que se modifica por la asignación de segmentos:
>>> p[2:4]
[''T'',''h'']
>>> p[2:4] = [''t'',''r'']
>>> p
[''P'',''y'',''t'',''r'',''o'',''n'']
La tercera regla de asignación de segmentos es que la lista asignada (iterable) no tiene que tener la misma longitud; la porción indexada simplemente se corta y se reemplaza en masa por lo que se asigna:
>>> 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 más difícil de acostumbrarse es la asignación a segmentos vacíos. Usando los heurísticos 1 y 2 es fácil hacer que tu cabeza esté alrededor del índice de una porción vacía:
>>> 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]
[]
Y luego, una vez que haya visto eso, la asignación de división a la división vacía también tiene sentido:
>>> 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
Tenga en cuenta que, dado que no estamos cambiando el segundo número de la división (4), los elementos insertados siempre se apilan contra la ''o'', incluso cuando estamos asignando la división vacía. Por lo tanto, la posición para la asignación de división vacía es la extensión lógica de las posiciones para las asignaciones de división no vacía.
Retrocediendo un poco, ¿qué sucede cuando continúas con nuestra procesión de contar el inicio de la porción?
>>> 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 rebanar, una vez que hayas terminado, has terminado; no comienza a cortar hacia atrás. En Python no obtienes zancadas negativas a menos que las pidas explícitamente usando un número negativo.
>>> p[5:3:-1]
[''n'',''o'']
Hay algunas consecuencias extrañas en la regla de "una vez que hayas terminado, hayas terminado":
>>> 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
De hecho, en comparación con la indexación, el corte de python es extrañamente a prueba de errores:
>>> p[100:200]
[]
>>> p[int(2e99):int(1e99)]
[]
Esto puede ser útil a veces, pero también puede llevar a un comportamiento algo extraño:
>>> 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'']
Dependiendo de tu aplicación, eso podría ... o no ... ¡ser lo que esperabas allí!
A continuación se encuentra el texto de mi respuesta original, ha sido útil para muchas personas, por lo que no quise borrarlo.
>>> 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]
Esto también puede aclarar la diferencia entre el corte y la indexación.
Me resulta más fácil recordar cómo funciona, luego puedo encontrar una combinación específica de inicio / parada / paso.
Es instructivo entender el range()
primero:
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
Comience desde el start
, aumente por step
, no llegue a stop
. Muy simple.
Lo que hay que recordar sobre el paso negativo es que stop
siempre es el extremo excluido, ya sea más alto o más bajo. Si desea la misma división en orden opuesto, es mucho más limpio hacer la reversión por separado: por ejemplo, ''abcde''[1:-2][::-1]
corta una charca desde la izquierda, dos desde la derecha, luego retrocede. (Ver también reversed()
.)
La división de secuencias es la misma, excepto que primero normaliza los índices negativos y nunca puede salir de la secuencia:
TODO : El código siguiente tenía un error con "nunca salir de la secuencia" cuando abs (paso)> 1; Creo que lo parché para ser correcto, pero es difícil de entender.
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]
No se preocupe por los detalles de " is None
, solo recuerde que omitir start
y / o stop
siempre hace lo correcto para darle toda la secuencia.
La normalización de los índices negativos primero permite que el inicio y / o la parada se cuenten desde el final de forma independiente: ''abcde''[1:-2] == ''abcde''[1:3] == ''bc''
pesar del range(1,-2) == []
. La normalización a veces se considera "módulo de la longitud", pero tenga en cuenta que agrega la longitud solo una vez: por ejemplo, ''abcde''[-53:42]
es solo la cadena completa.
Notación de corte de Python:
a[start:end:step]
- Para el
start
y elend
, los valores negativos se interpretan como relativos al final de la secuencia. - Los índices positivos para el
end
indican la posición después del último elemento que se incluirá. - Los valores en blanco están predeterminados de la siguiente manera:
[+0:-0:1]
. - Usar un paso negativo invierte la interpretación de
start
yend
La notación se extiende a matrices (numpy) y matrices multidimensionales. Por ejemplo, para cortar columnas enteras puede usar:
m[::,0:2:] ## slice the first two columns
Los segmentos contienen referencias, no copias, de los elementos de la matriz. Si desea hacer una copia separada de una matriz, puede usar deepcopy()
.
También puede usar la asignación de división para eliminar uno o más elementos de una lista:
r = [1, ''blah'', 9, 8, 2, 3, 4]
>>> r[1:4] = []
>>> r
[1, 2, 3, 4]
Utilizo el método de "un punto de índice entre elementos" para pensarlo, pero una forma de describirlo que a veces ayuda a otros a obtenerlo es esta:
mylist[X:Y]
X es el índice del primer elemento que desea.
Y es el índice del primer elemento que no desea.
Y un par de cosas que no eran inmediatamente obvias para mí cuando vi por primera vez la sintaxis de corte:
>>> x = [1,2,3,4,5,6]
>>> x[::-1]
[6,5,4,3,2,1]
Una manera fácil de revertir secuencias!
Y si quisiera, por alguna razón, cada segundo elemento en la secuencia invertida:
>>> x = [1,2,3,4,5,6]
>>> x[::-2]
[6,4,2]
Rebanada : - La serpiente aparece cerca de tu pie. Se mueve de lo invisible a lo visible. Nuestra visión revela (como una porción) solo una parte del mundo. de manera similar, una porción de Python extrae elementos, basados en un inicio y una parada. Tomamos rodajas en muchos tipos en Python. Especificamos un primer índice opcional, un último índice opcional y un paso opcional.
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.
Puede obtener buenos ejemplos en el siguiente enlace: - Ejemplo de notación de segmento de Python
El siguiente es el ejemplo de índice de una cadena
+---+---+---+---+---+
| H | e | l | p | A |
+---+---+---+---+---+
0 1 2 3 4 5
-5 -4 -3 -2 -1
str="Name string"
Ejemplo de rebanado: [inicio: fin: paso]
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
A continuación se muestra el ejemplo de uso.
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
En Python, la forma más básica de corte es la siguiente:
l[start:end]
donde l
es alguna colección, start
es un índice inclusivo y end
es un índice exclusivo.
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]
Al dividir desde el inicio, puede omitir el índice cero, y al dividir hasta el final, puede omitir el índice final ya que es redundante, así que no sea detallado:
In [5]: l[:3] == l[0:3]
Out[5]: True
In [6]: l[7:] == l[7:len(l)]
Out[6]: True
Los enteros negativos son útiles cuando se realizan desplazamientos relativos al final de una colección:
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]
Es posible proporcionar índices que están fuera de límites cuando se corta, como:
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]
Tenga en cuenta que el resultado de cortar una colección es una colección completamente nueva. Además, cuando se usa la notación de división en asignaciones, la longitud de la asignación de división no tiene que ser la misma. Los valores anteriores y posteriores a la división asignada se mantendrán, y la colección se reducirá o aumentará para contener los nuevos valores:
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]
Si omite el índice de inicio y fin, hará una copia de la colección:
In [14]: l_copy = l[:]
In [15]: l == l_copy and l is not l_copy
Out[15]: True
Si se omiten los índices de inicio y finalización al realizar una operación de asignación, todo el contenido de la colección se reemplazará con una copia de lo que se hace referencia:
In [20]: l[:] = list(''hello...'')
In [21]: l
Out[21]: [''h'', ''e'', ''l'', ''l'', ''o'', ''.'', ''.'', ''.'']
Además del corte básico, también es posible aplicar la siguiente notación:
l[start:end:step]
donde l
es una colección, start
es un índice inclusivo, end
es un índice exclusivo y step
es una zancada que puede usarse para capturar cada elemento número nl
.
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]
El uso step
proporciona un truco útil para revertir una colección en Python:
In [25]: l[::-1]
Out[25]: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
También es posible usar enteros negativos step
como el siguiente ejemplo:
In[28]: l[::-2]
Out[28]: [9, 7, 5, 3, 1]
Sin embargo, usar un valor negativo para step
podría llegar a ser muy confuso. Por otra parte, con el fin de ser Pythonic, debe evitarse el uso start
, end
y step
en una sola rebanada. En caso de que sea necesario, considere hacer esto en dos asignaciones (una para cortar y la otra para caminar).
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]
Jejeje, es un poco extraño verme intentando dar una explicación mejor y más sencilla después de más de 2600 votos sobre lo que se ha marcado como la respuesta correcta de Grew Hewgill.
Aquí vamos ...
En mi opinión, entenderás y memorizarás mejor la notación de corte de cadena de Python si la miras de la siguiente manera (sigue leyendo).
Trabajemos con la siguiente cadena ...
azString = "abcdefghijklmnopqrstuvwxyz"
Para aquellos que no saben, puede crear cualquier subcadena a partir del azString
uso de la notaciónazString[x:y]
Viniendo de otros lenguajes de programación, es cuando el sentido común se ve comprometido. ¿Qué son x y y?
Tuve que sentarme y ejecutar varios escenarios en mi búsqueda de una técnica de memorización que me ayude a recordar qué son xey, y me ayude a cortar las cuerdas correctamente en el primer intento.
Mi conclusión es que x e y deben verse como los índices de límites que rodean las cadenas que queremos extra. Así que deberíamos ver la expresión como azString[index1, index2]
o incluso más clara como azString[index_of_first_character, index_after_the_last_character]
.
Aquí hay un ejemplo de visualización de eso ...
Letters abcdefghij ... ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ Indexes 0 1 2 3 4 5 6 7 8 9 ... | | cdefgh index1 index2
Así que todo lo que tiene que hacer si desea establecer index1 e index2 en los valores que rodearán la subcadena deseada. Por ejemplo, para obtener la subcadena "cdefgh", puede usarla azString[2:8]
porque el índice en el lado izquierdo de "c" es 2 y el que está en el tamaño correcto de "h" es 8.
Recuerda, estamos estableciendo los límites.
Ese truco funciona todo el tiempo y es fácil de memorizar.
Espero que esto ayude.
La técnica básica de corte es definir el punto de inicio, el punto de parada y el tamaño del paso, también conocido como zancada.
Primero, crearemos una lista de valores para usar en nuestro corte.
Cree dos listas para dividir, la primera es una lista numérica del 1 al 9 (Lista A). El segundo es también una lista numérica, de 0 a 9 (Lista 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)
Indexa el número 3 de A y el número 6 de B.
print(A[2])
print(B[6])
Rebanado basico
La sintaxis de indexación extendida utilizada para la segmentación es aList [inicio: detener: paso]. El argumento de inicio y el argumento de paso están predeterminados en ninguno, el único argumento requerido es detener. ¿Notó que esto es similar a cómo se usó el rango para definir las listas A y B? Esto se debe a que el objeto de sector representa el conjunto de índices especificado por rango (inicio, parada, paso). Documentación de Python 3.4
Como puede ver, definir solo detener devuelve un elemento. Desde el inicio, el valor predeterminado es ninguno, esto se traduce en la recuperación de un solo elemento.
Es importante tener en cuenta que el primer elemento es el índice 0, NO el índice 1. Por eso utilizamos 2 listas para este ejercicio. Los elementos de la Lista A están numerados según la posición ordinal (el primer elemento es 1, el segundo elemento es 2, etc.) Los elementos de la Lista B son los números que se usarían para indexarlos ([0] para el primer elemento 0, etc. ).
Con la sintaxis de indexación extendida, recuperamos un rango de valores. Por ejemplo, todos los valores se recuperan con dos puntos.
A[:]
Para recuperar un subconjunto de elementos, es necesario definir las posiciones de inicio y parada.
Dado el patrón aList [inicio: detener], recupere los dos primeros elementos de la Lista A
Las respuestas anteriores no analizan la división de matrices multidimensionales, que es posible utilizando el famoso paquete numpy:
El corte también se aplica a matrices multidimensionales.
# 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]])
El ": 2" antes de la coma opera en la primera dimensión y el "0: 3: 2" después de la coma opera en la segunda dimensión.
Para obtener una cierta parte de un iterable (como una lista), aquí hay un ejemplo:
variable[number1:number2]
En este ejemplo, un número positivo para el número 1 es cuántos componentes quitas del frente. Un número negativo es exactamente lo contrario, cuántos guardas del final. Un número positivo para el número 2 indica cuántos componentes tiene la intención de mantener desde el principio, y un negativo es la cantidad que desea retirar del final. Esto es algo contrario a la intuición, pero es correcto al suponer que el corte de la lista es extremadamente útil.
La mayoría de las respuestas anteriores aclaran la notación Slice. La sintaxis de indexación extendida utilizada para la segmentación es algunos aList[start:stop:step]
ejemplos básicos son
Más ejemplos de rebanado: 15 rebanadas extendidas
Mi cerebro parece feliz de aceptar que lst[start:end]
contiene el start
artículo -th. Incluso podría decir que es un "supuesto natural".
Pero ocasionalmente aparece una duda y mi cerebro pide una confirmación de que no contiene el end
elemento -th.
En estos momentos me baso en este sencillo teorema:
for any n, lst = lst[:n] + lst[n:]
Esta bonita propiedad me dice que lst[start:end]
no contiene el end
elemento -th porque está en lst[end:]
.
Tenga en cuenta que este teorema es cierto para cualquiera n
en absoluto. Por ejemplo, puedes comprobar que
lst = range(10)
lst[:-42] + lst[-42:] == lst
devuelve True
.
Quiero agregar un ejemplo de Hello world que explique los conceptos básicos de las rebanadas para los principiantes. Me ayudó mucho.
Vamos a tener una lista con seis valores [''P'', ''Y'', ''T'', ''H'', ''O'', ''N'']
:
+---+---+---+---+---+---+
| P | Y | T | H | O | N |
+---+---+---+---+---+---+
0 1 2 3 4 5
Ahora las porciones más simples de esa lista son sus sublistas. La notación es [<index>:<index>]
y la clave es leerla así:
[ start cutting before this index : end cutting before this index ]
Ahora, si haces una parte [2:5]
de la lista anterior, esto sucederá:
| |
+---+---|---+---+---|---+
| P | Y | T | H | O | N |
+---+---|---+---+---|---+
0 1 | 2 3 4 | 5
Hizo un corte antes del elemento con índice 2
y otro corte antes del elemento con índice 5
. Entonces, el resultado será una división entre esos dos cortes, una lista [''T'', ''H'', ''O'']
.
Si cree que los índices negativos en el corte es confuso, aquí tiene una manera muy fácil de pensar: simplemente reemplace el índice negativo len - index
. Entonces, por ejemplo, reemplaza -3 por len(list) - 3
.
La mejor manera de ilustrar lo que hace el corte interno es mostrarlo en el código que implementa esta operación:
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)]
#!/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)
Puede ejecutar este script y experimentar con él, a continuación se muestran algunos ejemplos que obtuve del script.
+---+---+---+---+---+---+---+---+---+
| C | O | M | P | U | T | E | R | S |
+---+---+---+---+---+---+---+---+---+
0 1 2 3 4 5 6 7 8 9
-9 -8 -7 -6 -5 -4 -3 -2 -1
COMPUTERS[ 4 : 7 ] = UTE
COMPUTERS[ 2 : 5 : 2 ] = MU
COMPUTERS[-5 : 1 :-1 ] = UPM
COMPUTERS[ 4 ] = U
COMPUTERS[-4 :-6 :-1 ] = TU
COMPUTERS[ 2 :-3 : 1 ] = MPUT
COMPUTERS[ 2 :-3 :-1 ] =
COMPUTERS[ : :-1 ] = SRETUPMOC
COMPUTERS[-5 : ] = UTERS
COMPUTERS[-5 : 0 :-1 ] = UPMO
COMPUTERS[-5 : :-1 ] = UPMOC
COMPUTERS[-1 : 1 :-2 ] = SEUM
[Finished in 0.9s]
Cuando use un paso negativo, observe que la respuesta se desplaza hacia la derecha en 1.
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 :
|--------------->
<---------------|
Espero que esto te ayude a modelar la lista en Python.
Referencia: http://wiki.python.org/moin/MovingToPythonFromOtherLanguages