Eu tenho uma lista de tuplas de 2 itens e gostaria de convertê-las em 2 listas, onde o primeiro contém o primeiro item em cada tupla e a segunda lista contém o segundo item.
Por exemplo:
original = [('a', 1), ('b', 2), ('c', 3), ('d', 4)]
# and I want to become...
result = (['a', 'b', 'c', 'd'], [1, 2, 3, 4])
Existe uma função interna que faz isso?
Respostas:
zip
é o seu próprio inverso! Desde que você use o operador especial *.A maneira como isso funciona é chamando
zip
com os argumentos:… Exceto que os argumentos são passados
zip
diretamente (após serem convertidos em uma tupla), então não há necessidade de se preocupar com o número de argumentos que estão ficando muito grandes.fonte
zip([], [])
dessa maneira não o leva a você[], []
. Isso te pega[]
. Se apenas ...zip
funciona exatamente da mesma maneira no Python 3, exceto pelo fato de retornar um iterador em vez de uma lista. A fim de obter o mesmo resultado como acima você só precisa quebrar a chamada zip em uma lista:list(zip(*[('a', 1), ('b', 2), ('c', 3), ('d', 4)]))
saída de vontade[('a', 'b', 'c', 'd'), (1, 2, 3, 4)]
list
s estão bem. Mas, se você tentar obter o resultado completo de uma só vez (selist
o resultado forzip
), poderá usar muita memória (porque todos ostuple
s devem ser criados ao mesmo tempo). Se você puder apenas iterar o resultadozip
semlist
negar, economizará muita memória. A única outra preocupação é se a entrada possui muitos elementos; o custo é que ele deve descompactá-los todos como argumentos ezip
precisará criar e armazenar iteradores para todos eles. Este é apenas um problema real com s muito longoslist
(pense em centenas de milhares de elementos ou mais).Você também pode fazer
Ele deve dimensionar melhor. Especialmente se o Python fizer bom em não expandir as compreensões da lista, a menos que seja necessário.
(Aliás, ele cria duas tuplas (par) de listas, em vez de uma lista de tuplas, como
zip
faz.)Se geradores, em vez de listas reais, estiverem ok, isso faria o seguinte:
Os geradores não vasculham a lista até você solicitar cada elemento, mas, por outro lado, eles mantêm referências à lista original.
fonte
zip(*x)
versão.zip(*x)
requer apenas uma passagem pelo loop e não utiliza elementos de pilha.zip
se o caso de uso é que os dados transpostos são usados e descartados imediatamente, enquanto as listas originais permanecem na memória por muito mais tempo.Se você possui listas que não têm o mesmo tamanho, pode não querer usar o zip conforme a resposta do Patricks. Isso funciona:
Mas com listas de tamanhos diferentes, o zip trunca cada item para o comprimento da lista mais curta:
Você pode usar o mapa sem função para preencher resultados vazios com Nenhum:
zip () é um pouco mais rápido.
fonte
izip_longest
zip_longest
para usuários python3.Eu gosto de usar
zip(*iterable)
(que é o pedaço de código que você está procurando) nos meus programas da seguinte forma:Acho
unzip
mais legível.fonte
Dá uma tupla de listas como na pergunta.
Descompacta as duas listas.
fonte
Abordagem ingênua
funciona bem para iterável finito (por exemplo, seqüências como
list
/tuple
/str
) de iteráveis (potencialmente infinitos) que podem ser ilustrados comoOnde
n in ℕ
,a_ij
corresponde aoj
-th elemento dei
-th iterável,e depois de aplicar
transpose_finite_iterable
chegamosExemplo em Python desse caso em que
a_ij == j
,n == 2
Mas não podemos usar
transpose_finite_iterable
novamente para retornar à estrutura do original,iterable
porqueresult
é um iterável infinito de iteráveis finitos (tuple
s no nosso caso):Então, como podemos lidar com este caso?
... e aqui vem o
deque
Depois de examinarmos os documentos de
itertools.tee
função , há uma receita Python que, com algumas modificações, pode ajudar no nosso casovamos checar
Síntese
Agora podemos definir a função geral para trabalhar com iteráveis de iteráveis, das quais são finitas e outras são potencialmente infinitas usando
functools.singledispatch
decorador comoque pode ser considerado como seu próprio inverso (os matemáticos chamam esse tipo de função de "involuções" ) na classe de operadores binários sobre iteráveis finitos e não vazios.
Como bônus de
singledispatch
ing, podemos lidar comnumpy
matrizes comoe depois usá-lo como
Nota
Desde que
transpose
retorna iteradores e se alguém quiser ter umtuple
delist
s como no OP - isso pode ser feito adicionalmente commap
a função incorporada comoPropaganda
Eu adicionei uma solução generalizada ao
lz
pacote da0.5.0
versão que pode ser usada comoPS
Não há solução (pelo menos óbvia) para lidar com iterável potencialmente infinito de iteráveis potencialmente infinitos, mas esse caso é menos comum.
fonte
É apenas outra maneira de fazer isso, mas me ajudou muito, então eu escrevo aqui:
Tendo esta estrutura de dados:
Resultando em:
A maneira mais pitônica de descompactá-lo e voltar ao original é esta na minha opinião:
Mas isso retorna uma tupla, portanto, se você precisar de uma lista, poderá usar:
fonte
Considere usar more_itertools.unzip :
fonte
Como retorna tuplas (e pode usar toneladas de memória), o
zip(*zipped)
truque parece mais inteligente do que útil para mim.Aqui está uma função que realmente fornecerá o inverso do zip.
fonte
Nenhuma das respostas anteriores fornece com eficiência a saída necessária, que é uma tupla de listas , em vez de uma lista de tuplas . Para o primeiro, você pode usar
tuple
commap
. Aqui está a diferença:Além disso, a maioria das soluções anteriores assume o Python 2.7, onde
zip
retorna uma lista em vez de um iterador.Para o Python 3.x, você precisará passar o resultado para uma função como
list
outuple
para esgotar o iterador. Para iteradores com eficiência de memória, você pode omitir o externolist
etuple
solicitar as respectivas soluções.fonte
Embora
zip(*seq)
seja muito útil, pode não ser adequado para seqüências muito longas, pois criará uma tupla de valores a serem passados. Por exemplo, eu tenho trabalhado com um sistema de coordenadas com mais de um milhão de entradas e acho significativamente mais rápido criar as sequências diretamente.Uma abordagem genérica seria algo como isto:
Mas, dependendo do que você deseja fazer com o resultado, a escolha da coleção pode fazer uma grande diferença. No meu caso de uso real, o uso de conjuntos e nenhum loop interno é notavelmente mais rápido que todas as outras abordagens.
E, como outros observaram, se você estiver fazendo isso com conjuntos de dados, pode fazer sentido usar as coleções Numpy ou Pandas.
fonte
Embora matrizes e pandas numpy possam ser preferíveis, essa função imita o comportamento de
zip(*args)
quando chamado comounzip(args)
.Permite que os geradores sejam transmitidos conforme
args
itera através dos valores. Decorecls
e / oumain_cls
microgerencie a inicialização do contêiner.fonte