¿Qué es :: (doble colon) en Python cuando se suscriben secuencias?

264

Sé que puedo usar algo como string[3:4]obtener una subcadena en Python, pero ¿qué significa el 3 en somesequence[::3]?

Aillyn
fuente
lo que quiere decir que viene antes :: igual [5::]. Entonces, ¿qué quiere decir con 5?
Umar Asghar
1
[5 ::] significaría comenzar con el primer elemento, nada para el segundo y seleccionar el siguiente elemento
Gagan

Respuestas:

243

significa "nada para el primer argumento, nada para el segundo, y saltar por tres". Obtiene cada tercer elemento de la secuencia en rodajas. Rebanadas extendidas es lo que quieres. Nuevo en Python 2.3

Adriano Varoli Piazza
fuente
99
También se puede usar para revertir una lista usando [:: - 1]
thavan
22
Devuelve cada elemento en una posición que es múltiplo de 3 . Como 3 * 0 = 0, devuelve también el elemento en la posición 0. Por ejemplo: range(10)[::3]salidas[0, 3, 6, 9]
Ricky Robinson
1
¿Qué significa quién viene antes ::como [n ::]. Entonces, ¿qué quiere decir con n?
Umar Asghar
154

Las direcciones de división de secuencia de Python se pueden escribir como [inicio: fin: paso] y se puede descartar cualquiera de inicio, detención o finalización. a[::3]es cada tercer elemento de la secuencia.

deinst
fuente
85

seq[::n]es una secuencia de cada nelemento en la secuencia completa.

Ejemplo:

>>> range(10)[::2]
[0, 2, 4, 6, 8]

La sintaxis es:

seq[start:end:step]

Entonces puedes hacer:

>>> range(100)[5:18:2]
[5, 7, 9, 11, 13, 15, 17]
Yuval Adam
fuente
44
En Python 3, su rango de ejemplo (N) [:: paso] produce un objeto de rango, no una lista. Para ver realmente lo que está sucediendo, debe forzar el rango a una lista, matriz np, etc.
PikalaxALT
57

Explicación

s[i:j:k]es, según la documentación , "segmento de s de i a j con el paso k". Cuando iy jestán ausentes, se asume toda la secuencia y, por lo tanto, s[::k]significa "cada elemento k-ésimo".

Ejemplos

Primero, inicialicemos una lista:

>>> s = range(20)
>>> s
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

Tomemos cada 3 rd elemento desde s:

>>> s[::3]
[0, 3, 6, 9, 12, 15, 18]

Tomemos cada 3 rd elemento desde s[2:]:

>>> s[2:]
[2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
>>> s[2::3]
[2, 5, 8, 11, 14, 17]

Tomemos cada 3 rd elemento desde s[5:12]:

>>> s[5:12]
[5, 6, 7, 8, 9, 10, 11]
>>> s[5:12:3]
[5, 8, 11]

Tomemos cada 3 rd elemento desde s[:10]:

>>> s[:10]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> s[:10:3]
[0, 3, 6, 9]
Bolo
fuente
respuesta asombrosa!
Jürgen K.
30

TL; DR

Este ejemplo visual le mostrará cómo seleccionar elementos cuidadosamente en una matriz NumPy (matriz bidimensional) de una manera bastante entretenida (lo prometo). El paso 2 a continuación ilustra el uso de esos "dos puntos dobles" ::en cuestión.

(Precaución: este es un ejemplo específico de matriz NumPy con el objetivo de ilustrar el caso de uso de "dos puntos dobles" ::para saltar elementos en varios ejes. Este ejemplo no cubre las estructuras de datos nativas de Python List).

Un ejemplo concreto para gobernarlos a todos ...

Digamos que tenemos una matriz NumPy que se ve así:

In [1]: import numpy as np

In [2]: X = np.arange(100).reshape(10,10)

In [3]: X
Out[3]:
array([[ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
       [20, 21, 22, 23, 24, 25, 26, 27, 28, 29],
       [30, 31, 32, 33, 34, 35, 36, 37, 38, 39],
       [40, 41, 42, 43, 44, 45, 46, 47, 48, 49],
       [50, 51, 52, 53, 54, 55, 56, 57, 58, 59],
       [60, 61, 62, 63, 64, 65, 66, 67, 68, 69],
       [70, 71, 72, 73, 74, 75, 76, 77, 78, 79],
       [80, 81, 82, 83, 84, 85, 86, 87, 88, 89],
       [90, 91, 92, 93, 94, 95, 96, 97, 98, 99]])

Digamos por alguna razón, su jefe quiere que seleccione los siguientes elementos:

ingrese la descripción de la imagen aquí

"¿Pero cómo?" ... ¡Sigue leyendo! (Podemos hacer esto en un enfoque de 2 pasos)

Paso 1 - Obtenga el subconjunto

Especifique el "índice de inicio" y el "índice de finalización" en las direcciones de fila y columna.

ingrese la descripción de la imagen aquí

En codigo:

In [5]: X2 = X[2:9,3:8]

In [6]: X2
Out[6]:
array([[23, 24, 25, 26, 27],
       [33, 34, 35, 36, 37],
       [43, 44, 45, 46, 47],
       [53, 54, 55, 56, 57],
       [63, 64, 65, 66, 67],
       [73, 74, 75, 76, 77],
       [83, 84, 85, 86, 87]])

Observe ahora que acabamos de obtener nuestro subconjunto, con el uso de una simple técnica de indexación de inicio y fin. A continuación, cómo hacer ese "salto" ... (¡sigue leyendo!)

Paso 2: seleccione elementos (con el argumento "paso de salto")

Ahora podemos especificar los "pasos de salto" en direcciones de fila y de columna (para seleccionar elementos de forma "de salto") de esta manera:

ingrese la descripción de la imagen aquí

En el código (tenga en cuenta los dos puntos dobles):

In [7]: X3 = X2[::3, ::2]

In [8]: X3
Out[8]:
array([[23, 25, 27],
       [53, 55, 57],
       [83, 85, 87]])

¡Acabamos de seleccionar todos los elementos según sea necesario! :)

 Consolidar el Paso 1 (inicio y final) y el Paso 2 ("saltar")

Ahora que conocemos el concepto, podemos combinar fácilmente el paso 1 y el paso 2 en un solo paso consolidado, para ser compactos:

In [9]: X4 = X[2:9,3:8][::3,::2]

    In [10]: X4
    Out[10]:
    array([[23, 25, 27],
           [53, 55, 57],
           [83, 85, 87]])

¡Hecho!

Atlas7
fuente
¿Qué sucede si quiero establecer cada una de esas entradas marcadas en 0 en el objeto original? ¿Cómo proceder?
user1211030
1
Haga un X[2:9,3:8][::3,::2] = 0 (para reemplazar las entradas marcadas a 0). Si Xvuelve a escribir , verá que todas las entradas marcadas ahora están configuradas en 0.
Atlas7
15

Al cortar en Python, el tercer parámetro es el paso. Como otros mencionaron, vea Slices extendidos para una buena descripción.

Con este conocimiento, [::3]solo significa que no ha especificado ningún índice inicial o final para su segmento. Como ha especificado un paso, 3esto requerirá cada tercera entrada para somethingcomenzar en el primer índice. Por ejemplo:

>>> '123123123'[::3]
'111'
Justin Ethier
fuente
7

También puede usar esta notación en sus propias clases personalizadas para que haga lo que quiera

class C(object):
    def __getitem__(self, k):
        return k

# Single argument is passed directly.
assert C()[0] == 0

# Multiple indices generate a tuple.
assert C()[0, 1] == (0, 1)

# Slice notation generates a slice object.
assert C()[1:2:3] == slice(1, 2, 3)

# If you omit any part of the slice notation, it becomes None.
assert C()[:] == slice(None, None, None)
assert C()[::] == slice(None, None, None)
assert C()[1::] == slice(1, None, None)
assert C()[:2:] == slice(None, 2, None)
assert C()[::3] == slice(None, None, 3)

# Tuple with a slice object:
assert C()[:, 1] == (slice(None, None, None), 1)

# Ellipsis class object.
assert C()[...] == Ellipsis

Entonces podemos abrir objetos de corte como:

s = slice(1, 2, 3)
assert s.start == 1
assert s.stop == 2
assert s.step == 3

Esto se usa notablemente en Numpy para cortar matrices multidimensionales en cualquier dirección.

Por supuesto, cualquier API sensata debería usarse ::3con la semántica habitual "cada 3".

Lo relacionado Ellipsisse trata más adelante en: ¿Qué hace el objeto de puntos suspensivos?

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
fuente
6

El tercer parámetro es el paso. Entonces [:: 3] devolvería cada 3er elemento de la lista / cadena.

mshafrir
fuente
4

Python usa :: para separar el valor de Fin, el Inicio y el Paso.

PODERRANGERDUDEONCAPS
fuente
1
Esto no proporciona suficientes detalles para ser realmente útil.
bstpierre
44
¿No te refieres a "el comienzo, el final y el paso"? Parece engañoso enumerarlos fuera de servicio.
Jon Coombs