web-dev-qa-db-ja.com

タプルのリストから複数のフィールドを抽出するリスト内包表記

タプルのリストがあります

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

次のように最初の2つのフィールドのみを持つ新しいリストを作成します。

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

しかし、複数の要素のリスト理解を作成する方法がわかりません。

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

ループを使用するよりもPythonicの方法を学ぶほうが好きです-何が間違っていますか?

18
Bill

extended iterable unpacking を使用できます。

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

_を使い捨てのプレースホルダー名として使用することは一般的な規則です。

37
timgeb

あなたがやっていたことはほぼ正しいことでした。リスト内の各タプルを新しいタプルに変換しようとしました。しかし、実際にタプルを宣言するのを忘れました。それが括弧がしていることです:

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

基本的なスライシングを使用します。これには、リスト要素のいずれかにサブ要素の予想数がない場合でも失敗しないという利点があります。

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

itemgetter を使用できます。

from operator import itemgetter


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

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

print(result)

出力

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

より読みやすい代替手段は次のとおりです。

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