Erlang e Ruby vêm com funções para achatar matrizes. Parece uma ferramenta tão simples e útil para adicionar a um idioma. Pode-se fazer isso:
>>> mess = [[1, [2]], 3, [[[4, 5]], 6]]
>>> mess.flatten()
[1, 2, 3, 4, 5, 6]
Ou até:
>>> import itertools
>>> mess = [[1, [2]], 3, [[[4, 5]], 6]]
>>> list(itertools.flatten(mess))
[1, 2, 3, 4, 5, 6]
Em vez disso, no Python, é preciso passar pelo trabalho de escrever uma função para achatar matrizes do zero. Isso me parece bobo, achatar matrizes é uma coisa tão comum a se fazer. É como ter que escrever uma função personalizada para concatenar duas matrizes.
Eu pesquisei isso no Google sem frutos, então estou perguntando aqui; existe uma razão específica para uma linguagem madura como o Python 3, que vem com centenas de milhares de baterias incluídas, não fornecer um método simples de achatar matrizes? A ideia de incluir tal função foi discutida e rejeitada em algum momento?
python
python-3.x
Hubro
fonte
fonte
extend
mas achatar teria sido muito mais elegante. No entanto, pergunto se esse padrão é comum o suficiente para justificar o achatamento na biblioteca padrão.Respostas:
As propostas para uma
flatten
função a ser adicionada à biblioteca padrão aparecem periodicamente nas listas de discussão python-dev e python-ideas . Os desenvolvedores de Python geralmente respondem com os seguintes pontos:Um nivelamento de um nível (transformando um iterável de iterável em um único iterável) é uma expressão trivial de uma linha
(x for y in z for x in y)
e, em qualquer caso, já está na biblioteca padrão com o nomeitertools.chain.from_iterable
.Quais são os casos de uso para um nivelamento de múltiplos níveis de uso geral? São realmente atraentes o suficiente para que a função seja adicionada à biblioteca padrão?
Como um achatador multi-nível de uso geral decidirá quando achatar e quando sair sozinho? Você pode pensar que uma regra como "achatar qualquer coisa que suporte a interface iterável" funcionaria, mas isso levaria a um loop infinito para
flatten('a')
.Veja, por exemplo, Raymond Hettinger :
fonte
flatten
função de um nível pode ser definida comolambda z: [x for y in z for x in y]
.flatten
método. A implementação desse método deve recursivamente chamarflatten
seu subcomponente, se o objeto for um composto. Infelizmente, o AFAIK nem todo valor é um objeto no Python. No Ruby, ele deve funcionar.Ele vem com esse método, mas não o chama achatado. É chamado de " cadeia ". Ele retorna um iterador no qual você precisará usar a função list () para transformá-lo novamente em uma lista. Se você não quiser usar um *, poderá usar a segunda versão "from_iterator". Funciona da mesma maneira no Python 3. Ele falhará se a entrada da lista não for uma lista de listas.
Houve uma vez um método flatten no módulo compiler.ast, mas este foi preterido no 2.6 e depois removido no 3.0. A recursão arbitrária em profundidade, necessária para listas aninhadas arbitrariamente, não funciona bem com a profundidade máxima recursiva conservadora do Python. O motivo para a remoção do compilador deveu-se em grande parte ao fato de ser uma bagunça . O compilador foi transformado em ast, mas o achatamento foi deixado para trás.
A profundidade arbitrária pode ser alcançada com os arrays de numpy e o achatamento dessa biblioteca.
fonte
chain.from_iterator
função, como você disse, só pode ser usada para achatar listas bidimensionais. Um actualy função achatar, que aceita quaisquer quantidades de listas aninhadas e retorna uma lista unidimensional, ainda seria maciçamente útil em muitos casos (pelo menos na minha opinião)... talvez porque não seja tão difícil escrever você mesmo
... e depois achatar tudo o que quiser :)
fonte