web-dev-qa-db-fra.com

Compréhension des listes pour extraire plusieurs champs de la liste des tuples

J'ai une liste de tuples

servers = [('server1', 80 , 1, 2), ('server2', 443, 3, 4)]

Je veux créer une nouvelle liste qui n'a que les deux premiers champs comme dans:

 [('server1', 80), ('server2', 443)]

mais je ne vois pas comment créer une compréhension de liste pour plus d'un élément.

hosts = [x[0] for x in servers]  # this works to give me ['server1', server2']

hostswithports = [x[0], x[1] for x in servers] # this does not work

Je préfère apprendre la méthode Pythonic vs utiliser une boucle - qu'est-ce que je fais mal?

18
Bill

Vous pouvez utiliser déballage itératif étend .

>>> servers = [('server1', 80 , 1, 2), ('server2', 443, 3, 4)]
>>> [(server, port) for server, port, *_ in servers]
[('server1', 80), ('server2', 443)]

En utilisant _ comme nom d'espace réservé jetable est une convention courante.

37
timgeb

Ce que vous faisiez était presque correct. Vous tentiez de traduire chaque tuple de votre liste en un nouveau tuple. Mais vous avez oublié de déclarer le tuple. Voilà ce que font les parenthèses:

hosts = [(x[0], x[1]) for x in servers]
15
Woody1193

Utiliser le découpage de base, qui a l'avantage de ne pas échouer si l'un des éléments de votre liste ne possède pas le nombre attendu de sous-éléments.

[el[:2] for el in servers]
[('server1', 80), ('server2', 443)]
15
user3483203

Vous pouvez utiliser itemgetter :

from operator import itemgetter


servers = [('server1', 80 , 1, 2), ('server2', 443, 3, 4)]

result = list(map(itemgetter(0, 1), servers))

print(result)

Sortie

[('server1', 80), ('server2', 443)]

Une alternative plus lisible est la suivante:

from operator import itemgetter

get_server_and_port = itemgetter(0, 1)
servers = [('server1', 80, 1, 2), ('server2', 443, 3, 4)]
result = [get_server_and_port(e) for e in servers]

print(result)  # [('server1', 80), ('server2', 443)]
7
Daniel Mesejo