list função - Entendendo a notação de fatia do Python



len slice (25)

Eu preciso de uma boa explicação (referências são uma vantagem) na notação de fatia do Python.

Para mim, esta notação precisa de um pouco de recuperação.

Parece extremamente poderoso, mas ainda não entendi direito.


Answers

E algumas coisas que não eram imediatamente óbvias para mim quando vi pela primeira vez a sintaxe do fatiamento:

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

Maneira fácil de reverter seqüências!

E se você quisesse, por algum motivo, cada segundo item na seqüência invertida:

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

As respostas acima não discutem o fatiamento da matriz multi-dimensional que é possível usando o pacote numpy famoso:

O fatiamento também se aplica a matrizes multidimensionais.

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

O ": 2" antes da vírgula opera na primeira dimensão e o "0: 3: 2" após a vírgula operar na segunda dimensão.


Encontrei esta excelente tabela em http://wiki.python.org/moin/MovingToPythonFromOtherLanguages

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

Eu acho mais fácil lembrar como funciona, então eu posso descobrir qualquer combinação específica de iniciar / parar / passo.

É instrutivo entender o range() primeiro:

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

Comece do start , incremente step , não alcance a stop . Muito simples.

A coisa a lembrar sobre o passo negativo é que a stop é sempre o fim excluído, seja mais alto ou mais baixo. Se você quiser a mesma fatia na ordem oposta, é muito mais limpo fazer a reversão separadamente: por exemplo, 'abcde'[1:-2][::-1] corta um char da esquerda, dois da direita e depois inverte. (Veja também reversed() .)

O fatiamento de sequência é o mesmo, exceto que primeiro normaliza os índices negativos e nunca pode sair da sequência:

TODO : O código abaixo tinha um bug com "nunca sair da sequência" quando abs (passo)> 1; Acho que corrigi tudo para estar correto, mas é 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]

Não se preocupe com os Detalhes do is None - lembre-se que omitir start e / ou stop sempre faz a coisa certa para lhe dar toda a seqüência.

A normalização dos índices negativos primeiro permite que o início e / ou a parada sejam contados a partir do final independentemente: 'abcde'[1:-2] == 'abcde'[1:3] == 'bc' apesar do range(1,-2) == [] A normalização é algumas vezes considerada como "modulo o comprimento" mas note que adiciona o comprimento apenas uma vez: eg 'abcde'[-53:42] é apenas a string inteira.


Eu quero adicionar um exemplo Hello world que explique os fundamentos das fatias para os iniciantes. Isto me ajudou bastante.

Vamos ter uma lista com seis valores ['P', 'Y', 'T', 'H', 'O', 'N']:

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

Agora, as fatias mais simples dessa lista são suas sub-listas. A notação é [<index>:<index>]e a chave é ler assim:

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

Agora, se você fizer uma parte [2:5]da lista acima, isso acontecerá:

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

Você fez um corte antes do elemento com índice 2e outro corte antes do elemento com índice 5. Então o resultado será uma fatia entre esses dois cortes, uma lista ['T', 'H', 'O'].


É bem simples:

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

Há também o valor do step , que pode ser usado com qualquer um dos itens acima:

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

O ponto-chave a ser lembrado é que o valor :end representa o primeiro valor que não está na fatia selecionada. Portanto, a diferença entre o end e o start é o número de elementos selecionados (se a step for 1, o padrão).

A outra característica é que o start ou end pode ser um número negativo , o que significa que conta a partir do final da matriz, em vez do início. Assim:

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

Da mesma forma, o step pode ser um 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

O Python é gentil com o programador se houver menos itens do que você pede. Por exemplo, se você pedir a[:-2] e a só contiver um elemento, você receberá uma lista vazia em vez de um erro. Às vezes você preferiria o erro, então você tem que estar ciente de que isso pode acontecer.


Enumerando as possibilidades permitidas pela 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]]

Naturalmente, se (high-low)%stride != 0 , então o ponto final será um pouco menor que high-1 .

Se stride for negativo, a ordem será alterada um pouco, já que estamos fazendo uma contagem regressiva:

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

O fatiamento estendido (com vírgulas e elipses) é usado principalmente apenas por estruturas de dados especiais (como o Numpy); as sequências básicas não as suportam.

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

#!/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)

Você pode executar este script e experimentá-lo, abaixo estão alguns exemplos que recebi do 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]

Ao usar um passo negativo, observe que a resposta é deslocada para a direita em 1.


Como regra geral, escrever código com muitos valores de índice codificados leva a uma facilidade de leitura e manutenção. Por exemplo, se você voltar ao código um ano depois, você verá o que estava pensando ao escrevê-lo. A solução mostrada é simplesmente uma forma de indicar mais claramente o que seu código está realmente fazendo. Em geral, a fatia interna () cria um objeto de fatia que pode ser usado em qualquer lugar que uma fatia é permitida. Por exemplo:

>>> items = [0, 1, 2, 3, 4, 5, 6]
>>> a = slice(2, 4)
>>> items[2:4]
[2, 3]
>>> items[a]
[2, 3]
>>> items[a] = [10,11]
>>> items
[0, 1, 10, 11, 4, 5, 6]
>>> del items[a]
>>> items
[0, 1, 4, 5, 6]

Se você tiver uma instância de fatia s, poderá obter mais informações sobre ela observando seus atributos s.start, s.stop e s.step, respectivamente. Por exemplo:

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

Em Python, a forma mais básica de fatiar é a seguinte:

l[start:end]

onde lé alguma coleção, starté um índice inclusivo e endé um í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]

Ao fatiar a partir do início, você pode omitir o índice zero e, ao fatiar até o final, pode omitir o índice final, já que ele é redundante, portanto, não seja detalhado:

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

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

Inteiros negativos são úteis ao fazer offsets em relação ao final de uma coleção:

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]

É possível fornecer índices que estão fora dos limites ao fatiar, 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]

Tenha em mente que o resultado de fatiar uma coleção é uma coleção totalmente nova. Além disso, ao usar a notação de fatia nas atribuições, o comprimento da atribuição de fatia não precisa ser o mesmo. Os valores antes e depois da fatia atribuída serão mantidos e a coleção diminuirá ou aumentará para conter os novos 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]

Se você omitir o índice inicial e final, você fará uma cópia da coleção:

In [14]: l_copy = l[:]

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

Se os índices inicial e final forem omitidos ao executar uma operação de atribuição, todo o conteúdo da coleção será substituído por uma cópia do que é referenciado:

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

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

Além do fatiamento básico, também é possível aplicar a seguinte notação:

l[start:end:step]

onde lé uma coleção, starté um índice inclusivo, endé um índice exclusivo e stepé um passo que pode ser usado para levar todo item em 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]

Usar stepfornece um truque útil para reverter uma coleção no Python:

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

Também é possível usar números inteiros negativos stepcomo no exemplo a seguir:

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

No entanto, usar um valor negativo steppode se tornar muito confuso. Além disso, a fim de ser Pythonic, você deve evitar usar start, ende stepem uma única fatia. Caso isso seja necessário, considere fazer isso em duas tarefas (uma para dividir e outra para stride).

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]

No Python 2.7

Fatiar em Python

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)

Compreender a atribuição de índice é muito importante.

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

Quando você diz [a: b: c], você está dizendo, dependendo do sinal de c (para frente ou para trás), comece em a e termine em b (excluindo o elemento no índice bth). Use a regra de indexação acima e lembre-se de que você encontrará apenas elementos nesse intervalo:

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

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

Mas esse alcance continua infinitamente em ambas as direções:

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

Por exemplo:

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

Se a sua escolha de a, b e c permitir a sobreposição com o intervalo acima à medida que você percorre as regras para a, b, c acima, você obterá uma lista com elementos (tocados durante a travessia) ou obterá uma lista vazia.

Uma última coisa: se aeb são iguais, então você também recebe uma lista vazia:

             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

Você também pode usar a atribuição de fatia para remover um ou mais elementos de uma lista:

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

Notação de fatiamento de Python:

a[start:end:step]
  • Para start e end , os valores negativos são interpretados como sendo relativos ao final da sequência.
  • Índices positivos para end indicam a posição após o último elemento a ser incluído.
  • Valores em branco são padronizados da seguinte forma: [+0:-0:1] .
  • A utilização de um passo negativo inverte a interpretação do start e do end

A notação se estende a matrizes (numpy) e matrizes multidimensionais. Por exemplo, para dividir colunas inteiras, você pode usar:

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

Fatias retêm referências, não cópias, dos elementos da matriz. Se você quiser fazer uma cópia separada de um array, você pode usar deepcopy() .


O tutorial do Python fala sobre isso (role um pouco até chegar na parte sobre fatiar).

O diagrama de arte ASCII também é útil para lembrar como as fatias funcionam:

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

Uma maneira de lembrar como as fatias funcionam é pensar nos índices como apontando entre os caracteres, com a borda esquerda do primeiro caractere numerada como 0. Em seguida, a borda direita do último caractere de uma sequência de n caracteres possui o índice n .


Isto é como eu ensino fatias para iniciantes:

Entendendo a diferença entre indexação e fatiamento:

O Wiki Python tem essa incrível imagem que distingue claramente a indexação e o fatiamento.

É uma lista com 6 elementos. Para entender melhor o fatiamento, considere essa lista como um conjunto de seis caixas colocadas juntas. Cada caixa tem um alfabeto.

A indexação é como lidar com o conteúdo da caixa. Você pode verificar o conteúdo de qualquer caixa. Mas você não pode verificar o conteúdo de várias caixas de uma só vez. Você pode até mesmo substituir o conteúdo da caixa. Mas você não pode colocar 2 bolas em 1 caixa ou substituir 2 bolas de cada vez.

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

Slicing é como lidar com caixas em si. Você pode pegar a primeira caixa e colocá-la em outra mesa. Para pegar a caixa tudo que você precisa saber é a posição de início e fim da caixa.

Você pode até pegar as 3 primeiras caixas ou as últimas 2 caixas ou todas as caixas entre 1 e 4. Então, você pode escolher qualquer conjunto de caixas se você souber o começo e o fim. Essas posições são chamadas de posições de início e parada.

O interessante é que você pode substituir várias caixas de uma só vez. Você também pode colocar várias caixas onde você quiser.

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

Fatiar com o passo:

Até agora você escolheu caixas continuamente. Mas algumas vezes você precisa pegar discretamente. Por exemplo, você pode pegar cada segunda caixa. Você pode até pegar cada terceira caixa a partir do final. Esse valor é chamado de tamanho da etapa. Isso representa a lacuna entre suas captações sucessivas. O tamanho do passo deve ser positivo se você estiver escolhendo caixas do começo ao fim e vice-versa.

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

Como o Python descobre os parâmetros ausentes:

Ao fatiar se você deixar de fora qualquer parâmetro, o Python tentará descobrir isso automaticamente.

Se você verificar o código-fonte do CPython, você encontrará uma função chamada PySlice_GetIndicesEx, que descobre os índices para uma fatia para qualquer parâmetro dado. Aqui está o código equivalente lógico em Python.

Essa função usa um objeto Python e parâmetros opcionais para fatiar e retorna start, stop, step e slice length para a fatia solicitada.

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

Essa é a inteligência que está presente por trás das fatias. Como o Python tem uma função embutida chamada slice, você pode passar alguns parâmetros e verificar com que inteligência calcula parâmetros ausentes.

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

Nota: Este post foi originalmente escrito em meu blog http://www.avilpage.com/2015/03/a-slice-of-python-intelligence-behind.html


O abaixo é o exemplo do índice de uma string

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

str="Name string"

Exemplo de fatiamento: [start: end: step]

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

Abaixo está o exemplo 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

Meu cérebro parece feliz em aceitar que lst[start:end]contém o startitem -th. Eu posso até dizer que é uma 'suposição natural'.

Mas ocasionalmente uma dúvida se arrasta e meu cérebro pede que ele não contenha o end-ésimo elemento.

Nestes momentos, confio neste teorema simples:

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

Esta propriedade muito me diz que lst[start:end]não contém o enditem de -ésimo porque ele está em lst[end:].

Note que este teorema é verdadeiro para qualquer num. Por exemplo, você pode verificar isso

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

retorna True.


1. notação da fatia

Para simplificar, lembre-se que o slice tem apenas um formulário:

s[start:end:step]

e aqui está como funciona:

  • s : um objeto que pode ser cortado
  • start : primeiro índice para iniciar a iteração
  • end : last index, NOTE que o índice end não será incluído na fatia resultante
  • step : escolha elemento a cada step

Outra coisa importante: todo start , end , step pode ser omitido! E se eles forem omitidos, o valor padrão será usado: 0 , len(s) , 1 acordo.

Então possíveis variações são:

# mostly used variations
s[start:end]
s[start:]
s[:end]

# step related variations
s[:end:step]
s[start::step]
s[::step]

# make a copy
s[:]

NOTA: Se start>=end (considerando apenas quando o step>0 ), python retornará uma fatia vazia [] .

2. Armadilhas

A parte acima explica os principais recursos de como o slice funciona, ele funcionará na maioria das ocasiões. No entanto, pode haver armadilhas que você deve tomar cuidado, e essa parte as explica.

Índices negativos

A primeira coisa que confunde os aprendizes de Python é que o índice pode ser negativo! Não entre em pânico: o índice negativo significa contar de trás para frente.

Por exemplo:

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

Passo negativo

Tornar as coisas mais confusas também steppode ser negativo!

Etapa negativa significa iterar a matriz para trás: de ponta a ponta, com o índice final incluído e o índice inicial excluído do resultado.

NOTA : quando passo é negativo, o valor padrão para starta len(s)(enquanto endnão é igual a 0, porque s[::-1]contém s[0]). Por exemplo:

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

Erro fora do intervalo?

Surpreenda-se: o slice não aumenta IndexError quando o índice está fora do intervalo!

Se o índice estiver fora do intervalo, o python tentará configurar o índice para 0ou de len(s)acordo com a situação. Por exemplo:

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

Vamos terminar esta resposta com exemplos explica tudo o que discutimos:

# 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

Fatia : - cobra aparece perto do seu pé. Move-se do invisível para o visível. Nossa visão revela (como uma fatia) apenas uma parte do mundo. da mesma forma Uma fatia do Python extrai elementos, com base em um início e uma parada. Nós tomamos fatias em muitos tipos em Python. Nós especificamos um primeiro índice opcional, um último índice opcional e uma etapa 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.

você pode obter bons exemplos no link abaixo: - exemplo de notação de fatia python


Explique a notação de fatia do Python

Em suma, os dois-pontos (:) em notação subscrita ( subscriptable[subscriptarg] ) fazem a notação de fatia - que tem os argumentos opcionais, start , stop , step :

sliceable[start:stop:step]

O fatiamento em Python é uma maneira computacionalmente rápida de acessar metodicamente partes de seus dados. Na minha opinião, para ser um programador Python intermediário, é um aspecto da linguagem que é necessário estar familiarizado.

Definições importantes

Para começar, vamos definir alguns termos:

start: o índice inicial da fatia, incluirá o elemento nesse índice, a menos que seja o mesmo que stop , o padrão é 0, ou seja, o primeiro índice. Se for negativo, significa iniciar n itens do final.

stop: o índice final da fatia, ele não inclui o elemento neste índice, o padrão é o tamanho da seqüência que está sendo fatiada, ou seja, até e incluindo o final.

step: o valor pelo qual o índice aumenta, o padrão é 1. Se for negativo, você está cortando o iterável ao contrário.

Como funciona a indexação

Você pode fazer qualquer um desses números positivos ou negativos. O significado dos números positivos é simples, mas para números negativos, assim como índices em Python, você conta de trás para frente no início e no fim , e para o passo , simplesmente decrementa seu índice. Este exemplo é do tutorial da documentação , mas eu o modifiquei ligeiramente para indicar em qual item de uma sequência cada referência de índice:

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

Como funciona o fatiamento

Para usar a notação de fatia com uma sequência que a suporte, você deve incluir pelo menos dois pontos nos colchetes que seguem a sequência (que, na verdade, implementam o método __getitem__ da sequência, de acordo com o modelo de dados Python ).

A notação de fatia funciona assim:

sequence[start:stop:step]

E lembre-se de que há padrões para iniciar , parar e passo , portanto, para acessar os padrões, simplesmente deixe de fora o argumento.

Notação de fatia para obter os últimos nove elementos de uma lista (ou qualquer outra sequência que suporte, como uma string) seria assim:

my_list[-9:]

Quando vejo isso, leio a parte entre parênteses como "9 do final até o fim". (Na verdade, abrevio mentalmente como "-9, on")

Explicação:

A notação completa é

my_list[-9:None:None]

e para substituir os padrões (na verdade, quando step é negativo, o padrão de -len(my_list) - 1 é -len(my_list) - 1 , então None para stop realmente significa que ele vai para qualquer etapa final):

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

Os dois pontos , : , é o que diz ao Python que você está dando uma fatia e não um índice regular. É por isso que a maneira idiomática de criar uma cópia superficial de listas no Python 2 é

list_copy = sequence[:]

E limpá-los é com:

del my_list[:]

(O Python 3 obtém um método list.copy e list.clear .)

Quando o step é negativo, os padrões para start e stop mudança

Por padrão, quando o argumento da step está vazio (ou None ), ele é atribuído a +1 .

Mas você pode passar um número inteiro negativo e a lista (ou a maioria dos slicables padrão) será dividida do final para o início.

Assim, uma fatia negativa mudará os padrões para start e stop !

Confirmando isso na fonte

Eu gosto de incentivar os usuários a lerem a fonte e também a documentação. O código fonte para objetos de fatia e essa lógica é encontrado aqui . Primeiro, determinamos se o step é negativo:

 step_is_negative = step_sign < 0;

Nesse caso, o limite inferior é -1 o que significa que dividimos todo o caminho até e incluindo o início, e o limite superior é o comprimento menos 1, o que significa que começamos no final. (Note que a semântica deste -1 é diferente de um -1 que os usuários podem passar índices no Python indicando o último item.)

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

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

Caso contrário, o step é positivo, e o limite inferior será zero e o limite superior (que vamos até, mas não inclui), o comprimento da lista fatiada.

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

Então, podemos precisar aplicar os padrões para start e stop - o padrão para o start é calculado como o limite superior quando a step é negativa:

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

e stop , o limite inferior:

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

Dê às suas fatias um nome descritivo!

Você pode achar útil separar a formação da fatia passando-a para o método list.__getitem__ ( isso é o que os colchetes fazem ). Mesmo que você não seja novo, ele mantém seu código mais legível para que outros que tenham que ler seu código entendam mais facilmente o que você está fazendo.

No entanto, você não pode simplesmente atribuir alguns inteiros separados por dois pontos a uma variável. Você precisa usar o objeto de fatia:

last_nine_slice = slice(-9, None)

O segundo argumento, None , é necessário, de modo que o primeiro argumento seja interpretado como o argumento de start caso contrário, seria o argumento de stop .

Você pode então passar o objeto fatia para sua sequência:

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

É interessante que os intervalos também tenham fatias:

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

Considerações de memória:

Uma vez que fatias de listas do Python criam novos objetos na memória, outra função importante a ter em conta é itertools.islice . Normalmente, você desejará iterar sobre uma fatia e não apenas criá-la estaticamente na memória. islice é perfeito para isso. Uma ressalva, ele não suporta argumentos negativos para start , stop ou step , então, se isso é um problema, talvez seja necessário calcular índices ou reverter o iterável com antecedência.

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

e agora:

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

O fato de que as listas de listas fazem uma cópia é um recurso das próprias listas. Se você está cortando objetos avançados como um Pandas DataFrame, ele pode retornar uma visão do original, e não uma cópia.


Isto é apenas para mais informações ... Considere a lista abaixo

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)

Poucos outros truques para inverter a lista:

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]

Veja a resposta do abc acima


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 isso ajude você a modelar a lista em Python.

Referência: http://wiki.python.org/moin/MovingToPythonFromOtherLanguages


Eu uso o método "um ponto de índice entre os elementos" de pensar sobre ele mesmo, mas uma maneira de descrevê-lo, que às vezes ajuda os outros a entender, é esta:

mylist[X:Y]

X é o índice do primeiro elemento que você deseja.
Y é o índice do primeiro elemento que você não deseja.


A técnica básica de fatiamento é definir o ponto de partida, o ponto de parada e o tamanho do passo - também conhecido como passo.

Primeiro, vamos criar uma lista de valores para usar em nosso fatiamento.

Crie duas listas para dividir, a primeira é uma lista numérica de 1 a 9 (Lista A). O segundo também é uma 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)

Indexar o número 3 de A e o número 6 de B.

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

Fatias Básicas

A sintaxe de indexação estendida usada para fatiar é aList [start: stop: step]. O argumento start e o argumento step são padronizados para none - o único argumento obrigatório é stop. Você notou que isso é semelhante a como o intervalo foi usado para definir as listas A e B? Isso ocorre porque o objeto de fatia representa o conjunto de índices especificado por intervalo (iniciar, parar, etapa). Documentação do Python 3.4

Como você pode ver, definir apenas stop retorna um elemento. Como o padrão inicial é nenhum, isso se traduz em recuperar apenas um elemento.

É importante notar que o primeiro elemento é o índice 0, NÃO o índice 1. É por isso que estamos usando 2 listas para este exercício. Os elementos da Lista A são numerados de acordo com a posição ordinal (o primeiro elemento é 1, o segundo elemento é 2, etc) enquanto os elementos da Lista B são os números que seriam usados ​​para indexá-los ([0] para o primeiro elemento 0, etc ).

Com a sintaxe de indexação estendida, recuperamos um intervalo de valores. Por exemplo, todos os valores são recuperados com dois pontos.

A[:]

Para recuperar um subconjunto de elementos, as posições de início e parada precisam ser definidas.

Dado o padrão aList [start: stop], recupere os dois primeiros elementos da Listagem A


Bem, aqui está um código simples e não muito eficiente, mas para esse tamanho de conjunto de dados não há problema.

import numpy as np
grid = np.array([[0,0,0,0,0,0,0,0,0,0,0,0,0,0],
              [0,0,0,0,0,0,0,0,0.4,0.4,0.4,0,0,0],
              [0,0,0,0,0.4,1.4,1.4,1.8,0.7,0,0,0,0,0],
              [0,0,0,0,0.4,1.4,4,5.4,2.2,0.4,0,0,0,0],
              [0,0,0.7,1.1,0.4,1.1,3.2,3.6,1.1,0,0,0,0,0],
              [0,0.4,2.9,3.6,1.1,0.4,0.7,0.7,0.4,0.4,0,0,0,0],
              [0,0.4,2.5,3.2,1.8,0.7,0.4,0.4,0.4,1.4,0.7,0,0,0],
              [0,0,0.7,3.6,5.8,2.9,1.4,2.2,1.4,1.8,1.1,0,0,0],
              [0,0,1.1,5,6.8,3.2,4,6.1,1.8,0.4,0.4,0,0,0],
              [0,0,0.4,1.1,1.8,1.8,4.3,3.2,0.7,0,0,0,0,0],
              [0,0,0,0,0,0.4,0.7,0.4,0,0,0,0,0,0]])

arr = []
for i in xrange(grid.shape[0] - 1):
    for j in xrange(grid.shape[1] - 1):
        tot = grid[i][j] + grid[i+1][j] + grid[i][j+1] + grid[i+1][j+1]
        arr.append([(i,j),tot])

best = []

arr.sort(key = lambda x: x[1])

for i in xrange(5):
    best.append(arr.pop())
    badpos = set([(best[-1][0][0]+x,best[-1][0][1]+y)
                  for x in [-1,0,1] for y in [-1,0,1] if x != 0 or y != 0])
    for j in xrange(len(arr)-1,-1,-1):
        if arr[j][0] in badpos:
            arr.pop(j)


for item in best:
    print grid[item[0][0]:item[0][0]+2,item[0][1]:item[0][1]+2]

Basicamente, apenas faço um array com a posição do canto superior esquerdo e a soma de cada quadrado de 2x2 e classifico-o pela soma. Eu, então, pego o quadrado de 2x2 com a maior soma fora de disputa, coloco-o na bestmatriz e removo todos os outros quadrados de 2x2 que usaram qualquer parte deste quadrado de 2x2 removido.

Parece funcionar bem, exceto com a última pata (a que tem a menor soma na extrema direita da sua primeira foto). Acontece que existem outros dois quadrados 2x2 elegíveis com uma soma maior (e eles têm uma soma igual a entre si). Um deles ainda seleciona um quadrado do quadrado de 2x2, mas o outro está à esquerda. Felizmente, por sorte, vemos estar escolhendo mais do que você gostaria, mas isso pode exigir algumas outras idéias a serem usadas para obter o que você realmente quer o tempo todo.





python list slice