Em um programa que estou escrevendo, surgiu a necessidade de girar um array bidimensional. Procurando a solução ideal, encontrei este impressionante one-liner que faz o trabalho:
rotated = zip(*original[::-1])
Estou usando no meu programa agora e funciona como deveria. Meu problema, porém, é que não entendo como funciona.
Eu apreciaria se alguém pudesse explicar como as diferentes funções envolvidas alcançam o resultado desejado.
python
multidimensional-array
paldepind
fonte
fonte
Respostas:
Considere a seguinte lista bidimensional:
Vamos dividir passo a passo:
Essa lista é passada para o
zip()
uso de desempacotamento de argumento , então azip
chamada acaba sendo o equivalente a isto:Esperançosamente, os comentários deixam claro o que
zip
significa, ele agrupará os elementos de cada entrada iterável com base no índice ou, em outras palavras, agrupará as colunas.fonte
rotated = [list(r) for r in zip(*original[::-1])]
Essa é uma parte inteligente.
Primeiro, conforme observado em um comentário, em Python 3
zip()
retorna um iterador, então você precisa incluir tudolist()
para obter uma lista real de volta, então a partir de 2020 é realmente:Aqui está o detalhamento:
[::-1]
- faz uma cópia superficial da lista original na ordem inversa. Também poderia usar oreversed()
que produziria um iterador reverso sobre a lista em vez de realmente copiar a lista (mais eficiente em termos de memória).*
- torna cada sublista na lista original um argumento separado parazip()
(ou seja, descompacta a lista)zip()
- pega um item de cada argumento e faz uma lista (bem, uma tupla) a partir deles, e repete até que todas as sublistas sejam esgotadas. É aqui que a transposição realmente acontece.list()
converte a saída dezip()
em uma lista.Então, supondo que você tenha isso:
Primeiro você obtém isto (cópia superficial e invertida):
Em seguida, cada uma das sublistas é passada como um argumento para
zip
:zip()
consome repetidamente um item do início de cada um de seus argumentos e faz uma tupla a partir dele, até que não haja mais itens, resultando em (após ser convertido em uma lista):E Bob é seu tio.
Para responder à pergunta de @IkeMiguel em um comentário sobre girá-lo na outra direção, é bastante simples: você só precisa inverter as sequências que entram
zip
e o resultado. O primeiro pode ser alcançado removendo o[::-1]
e o segundo pode ser alcançado jogando um emreversed()
volta de tudo. Uma vez quereversed()
retorna um iterador sobre a lista, precisaremoslist()
contorná- lo para convertê-lo. Com algumaslist()
chamadas extras para converter os iteradores em uma lista real. Assim:Podemos simplificar isso um pouco usando a fatia "smiley marciano" em vez de
reversed()
... então não precisamos do exteriorlist()
:Claro, você também pode simplesmente girar a lista no sentido horário três vezes. :-)
fonte
zip
para uma lista no Python 3.x!Existem três partes para isso:
fonte
Apenas uma observação. A entrada é uma lista de listas, mas a saída da solução muito boa: rotated = zip (* original [:: - 1]) retorna uma lista de tuplas.
Isso pode ou não ser um problema.
No entanto, é facilmente corrigido:
A composição de lista ou o mapa converterão as tuplas internas de volta em listas.
fonte
fonte
Eu mesmo tive esse problema e encontrei a ótima página da wikipedia sobre o assunto (no parágrafo "Rotações comuns":
https://en.wikipedia.org/wiki/Rotation_matrix#Ambiguities
Então escrevi o seguinte código, super prolixo, para ter uma compreensão clara do que está acontecendo.
Espero que você ache útil cavar mais no muito bonito e inteligente one-liner que você postou.
Para testá-lo rapidamente, você pode copiar / colar aqui:
http://www.codeskulptor.org/
fonte
Girando no sentido anti-horário (coluna padrão para pivô de linha) como lista e ditado
Produz:
fonte
zip(*original[::-1])
funciona.