Extrair o primeiro item de cada sub-lista

146

Gostaria de saber qual é a melhor maneira de extrair o primeiro item de cada sublist em uma lista de listas e anexá-lo a uma nova lista. Então, se eu tiver:

lst = [[a,b,c], [1,2,3], [x,y,z]]

e eu quero sair a, 1e xe criar uma lista separada daqueles.

Eu tentei:

lst2.append(x[0] for x in lst)
Konrad
fonte
1
Seu código está quase correto. O único problema é o uso da compreensão da lista.
Abhishek Mittal

Respostas:

198

Usando a compreensão da lista :

>>> lst = [['a','b','c'], [1,2,3], ['x','y','z']]
>>> lst2 = [item[0] for item in lst]
>>> lst2
['a', 1, 'x']
alecxe
fonte
O método de compreensão de listas também é o mais rápido, ainda mais rápido que o método Numpy. A resposta de jboi fala sobre comparação de desempenho,
Qiao Zhang
83

Você pode usar o zip:

>>> lst=[[1,2,3],[11,12,13],[21,22,23]]
>>> zip(*lst)[0]
(1, 11, 21)

Ou, Python 3, onde zipnão produz uma lista:

>>> list(zip(*lst))[0]
(1, 11, 21)

Ou,

>>> next(zip(*lst))
(1, 11, 21)

Ou, (meu favorito), use numpy:

>>> import numpy as np
>>> a=np.array([[1,2,3],[11,12,13],[21,22,23]])
>>> a
array([[ 1,  2,  3],
       [11, 12, 13],
       [21, 22, 23]])
>>> a[:,0]
array([ 1, 11, 21])
dawg
fonte
Não obteve voto negativo, mas o primeiro trecho de código (o zip) produz: "o objeto 'zip' não é subscrito". Python 3.6 no Jupyter.
jboi
@jboi: Apenas envolva list-o primeiro ou use-o next. Obrigado
dawg
20

Teve o mesmo problema e ficou curioso sobre o desempenho de cada solução.

Aqui está o %timeit:

import numpy as np
lst = [['a','b','c'], [1,2,3], ['x','y','z']]

A primeira maneira numpy, transformando a matriz:

%timeit list(np.array(lst).T[0])
4.9 µs ± 163 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

Totalmente nativo usando compreensão de lista (como explicado por @alecxe):

%timeit [item[0] for item in lst]
379 ns ± 23.1 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

Outra maneira nativa de usar zip(como explicado por @dawg):

%timeit list(zip(*lst))[0]
585 ns ± 7.26 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

Segundo numpy-way. Também explicado por @dawg:

%timeit list(np.array(lst)[:,0])
4.95 µs ± 179 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

Surpreendentemente (bem, pelo menos para mim) a maneira nativa usando a compreensão de lista é a mais rápida e cerca de 10x mais rápida que a maneira numpy. A execução dos dois modos numpy sem a final listeconomiza cerca de um µs, o que ainda está na diferença de 10x.

Observe que, quando envolvi cada trecho de código com uma chamada para len, para garantir que os Geradores funcionassem até o final, o tempo permaneceu o mesmo.

jboi
fonte
4
há uma sobrecarga substancial ao criar uma matriz.
precisa saber é
1
concorde com hpaulj, se você começar com um array numpy, [:, 0] é mais rápido. Experimente: lst = np.array ([['a', 'b', 'c'], [1,2,3], ['x', 'y', 'z']]), então lst [: 0]. A conversão nos exemplos de contra-relógio oferece uma vantagem injusta à compreensão da lista. Portanto, se puder, use uma matriz numpy para armazenar seus dados se a velocidade for seu objetivo final. Numpy é quase sempre mais rápido. É construído para velocidade.
Spacedustpi
13

Python inclui uma função chamada itemgetter para retornar o item em um índice específico em uma lista:

from operator import itemgetter

Passe a função itemgetter () o índice do item que você deseja recuperar. Para recuperar o primeiro item, você usaria o itemgetter (0). O importante é entender que o itemgetter (0) em si retorna uma função. Se você passar uma lista para essa função, obtém o item específico:

itemgetter(0)([10, 20, 30]) # Returns 10

Isso é útil quando você o combina com map (), que assume uma função como seu primeiro argumento e uma lista (ou qualquer outro iterável) como o segundo argumento. Retorna o resultado da chamada da função em cada objeto no iterável:

my_list = [['a', 'b', 'c'], [1, 2, 3], ['x', 'y', 'z']]
list(map(itemgetter(0), my_list)) # Returns ['a', 1, 'x']

Observe que map () retorna um gerador; portanto, o resultado é passado para list () para obter uma lista real. Em resumo, sua tarefa pode ser feita assim:

lst2.append(list(map(itemgetter(0), lst)))

Esse é um método alternativo ao uso da compreensão de uma lista e o método a ser escolhido depende muito do contexto, legibilidade e preferência.

Mais informações: https://docs.python.org/3/library/operator.html#operator.itemgetter

Christian Abbott
fonte
2

Seu código está quase correto. O único problema é o uso da compreensão da lista.

Se você usar como: (x [0] para x em lst), ele retornará um objeto gerador. Se você usar como: [x [0] para x em lst], ele retornará uma lista.

Quando você anexa a saída de compreensão da lista a uma lista, a saída da compreensão da lista é o elemento único da lista.

lst = [["a","b","c"], [1,2,3], ["x","y","z"]]
lst2 = []
lst2.append([x[0] for x in lst])
print lst2[0]

lst2 = [['a', 1, 'x']]

lst2 [0] = ['a', 1, 'x']

Informe-me se estiver incorreto.

Abhishek Mittal
fonte
1
lst = [['a','b','c'], [1,2,3], ['x','y','z']]
outputlist = []
for values in lst:
    outputlist.append(values[0])

print(outputlist) 

Resultado: ['a', 1, 'x']

PrabhuPrakash
fonte
0

Você disse que tem uma lista existente. Então eu vou com isso.

>>> lst1 = [['a','b','c'], [1,2,3], ['x','y','z']]
>>> lst2 = [1, 2, 3]

Agora você está anexando o objeto gerador à sua segunda lista.

>>> lst2.append(item[0] for item in lst)
>>> lst2
[1, 2, 3, <generator object <genexpr> at 0xb74b3554>]

Mas você provavelmente quer que seja uma lista dos primeiros itens

>>> lst2.append([item[0] for item in lst])
>>> lst2
[1, 2, 3, ['a', 1, 'x']]

Agora, anexamos a lista dos primeiros itens à lista existente. Se você deseja adicionar os itens com temas, não uma lista deles, aos existentes, use list.extend. Nesse caso, não precisamos nos preocupar em adicionar um gerador, porque o prolongamento usará esse gerador para adicionar cada item recebido a partir daí, para estender a lista atual.

>>> lst2.extend(item[0] for item in lst)
>>> lst2
[1, 2, 3, 'a', 1, 'x']

ou

>>> lst2 + [x[0] for x in lst]
[1, 2, 3, 'a', 1, 'x']
>>> lst2
[1, 2, 3]

https://docs.python.org/3.4/tutorial/datastructures.html#more-on-lists https://docs.python.org/3.4/tutorial/datastructures.html#list-comprehensions

Hendrik
fonte
1
A sua resposta é agradável e completa para o que soa como o OP quer, mas eu acho que a palavra appendna questão está causando confusão. Parece que ele simplesmente quer a parte da compreensão da lista da sua solução.
Beroe