タプルのリストの最初の要素を取得するにはどうすればよいですか?


178

以下のようなリストがあり、最初の要素はIDで、もう1つは文字列です。

[(1, u'abc'), (2, u'def')]

以下のように、このタプルのリストからのみIDのリストを作成します。

[1,2]

このリストを使用する__inので、整数値のリストである必要があります。

回答:



68

zip関数を使用して要素を分離します。

>>> inpt = [(1, u'abc'), (2, u'def')]
>>> unzipped = zip(*inpt)
>>> print unzipped
[(1, 2), (u'abc', u'def')]
>>> print list(unzipped[0])
[1, 2]

編集(@BradSolomon):上記はPython 2.xで機能しzip、リストを返します。

Python 3.xでは、zipイテレータを返し、以下は上記と同等です。

>>> print(list(list(zip(*inpt))[0]))
[1, 2]

これには別のインポートが必要ですか?
JuliandotNut 2015

2
@JuliandotNutいいえ、組み込み関数です。(Python 2.x)
WayneSan 2015

22

こんな意味ですか

new_list = [ seq[0] for seq in yourlist ]

実際に持っているのはtupleオブジェクトのリストであり、セットのリストではありません(元の質問が暗示するように)。セットのリストである場合、セットには順序がないため、最初の要素はありません。

ここでは、1つの要素のタプルのリストを作成するよりも一般的に有用であると思われるため、ここではフラットリストを作成しました。しかし、あなただけで簡単に置き換えることにより、1つの要素のタプルのリストを作成することができますseq[0](seq[0],)


私はそれを試してみました。それは、このエラーを与える:int() argument must be a string or a number, not 'QuerySet'
wasimbhalli

4
@wasimbhalli- int()私の解決策のどこにもないので、あなたが見ている例外はコードの後で来る必要があります。
mgilson 2012

質問を更新しました。後で__inデータをフィルタリングするためにこのリストを使用する必要があります
wasimbhalli '27

なに__in?-指定した入力例に基づいて、整数のリストを作成します。ただし、タプルのリストが整数で始まっていない場合は、整数を取得できないため、を使用してそれらを整数にintするか、最初の要素を整数に変換できない理由を理解する必要があります。
mgilson 2012

DOESのnew_list = [ seq[0] for seq in yourlist if type(seq[0]) == int]作品?
pR0Ps 2012

11

「タプルアンパック」を使用できます。

>>> my_list = [(1, u'abc'), (2, u'def')]
>>> my_ids = [idx for idx, val in my_list]
>>> my_ids
[1, 2]

反復時に各タプルがアンパックされ、その値が変数idxandに設定されますval

>>> x = (1, u'abc')
>>> idx, val = x
>>> idx
1
>>> val
u'abc'

8

これがoperator.itemgetter目的です。

>>> a = [(1, u'abc'), (2, u'def')]
>>> import operator
>>> b = map(operator.itemgetter(0), a)
>>> b
[1, 2]

このitemgetterステートメントは、指定した要素のインデックスを返す関数を返します。書くのと全く同じ

>>> b = map(lambda x: x[0], a)

しかし、私はそれitemgetterがより明確でより明示的であると思います。

これは、コンパクトなソートステートメントを作成するのに便利です。例えば、

>>> c = sorted(a, key=operator.itemgetter(0), reverse=True)
>>> c
[(2, u'def'), (1, u'abc')]

7

パフォーマンスの観点から、python3.X

  • [i[0] for i in a]そしてlist(zip(*a))[0]同等です
  • 彼らはよりも速いです list(map(operator.itemgetter(0), a))

コード

import timeit


iterations = 100000
init_time = timeit.timeit('''a = [(i, u'abc') for i in range(1000)]''', number=iterations)/iterations
print(timeit.timeit('''a = [(i, u'abc') for i in range(1000)]\nb = [i[0] for i in a]''', number=iterations)/iterations - init_time)
print(timeit.timeit('''a = [(i, u'abc') for i in range(1000)]\nb = list(zip(*a))[0]''', number=iterations)/iterations - init_time)

出力

3.491014136001468e-05

3.422205176000717e-05


6

タプルが一意である場合、これは機能します

>>> a = [(1, u'abc'), (2, u'def')]
>>> a
[(1, u'abc'), (2, u'def')]
>>> dict(a).keys()
[1, 2]
>>> dict(a).values()
[u'abc', u'def']
>>> 

4
これは注文を失います。でも動作する可能性がordereddictあります。
Tim Tisdall

2つ以上のタプルの最初の要素が同じである場合、ソリューションは機能しません
kederrac

3

私が実行したとき(上記で提案したとおり):

>>> a = [(1, u'abc'), (2, u'def')]
>>> import operator
>>> b = map(operator.itemgetter(0), a)
>>> b

返す代わりに:

[1, 2]

これを返品として受け取りました:

<map at 0xb387eb8>

list()を使用する必要があることがわかりました。

>>> b = list(map(operator.itemgetter(0), a))

この提案を使用してリストを正常に返すため。とはいえ、この解決策には満足しています。ありがとうございます。(Spyder、iPythonコンソール、Python v3.6を使用してテスト/実行)


3

さまざまなアプローチの実行時間を比較することが有用であると考えていたので、ベンチマークを作成しました(simple_benchmarkライブラリを使用)

I)2つの要素を持つタプルを持つベンチマーク ここに画像の説明を入力してください

インデックスによってタプルから最初の要素を選択すると予想される場合がある0ので、正確に2つの値を期待することにより、アンパックソリューションに非常に近い最速のソリューションであることがわかります。

import operator
import random

from simple_benchmark import BenchmarkBuilder

b = BenchmarkBuilder()



@b.add_function()
def rakesh_by_index(l):
    return [i[0] for i in l]


@b.add_function()
def wayneSan_zip(l):
    return list(list(zip(*l))[0])


@b.add_function()
def bcattle_itemgetter(l):
     return list(map(operator.itemgetter(0), l))


@b.add_function()
def ssoler_upacking(l):
    return [idx for idx, val in l]

@b.add_function()
def kederrack_unpacking(l):
    return [f for f, *_ in l]



@b.add_arguments('Number of tuples')
def argument_provider():
    for exp in range(2, 21):
        size = 2**exp
        yield size, [(random.choice(range(100)), random.choice(range(100))) for _ in range(size)]


r = b.run()
r.plot()

II)2つ以上の要素を持つタプルを持つベンチマーク ここに画像の説明を入力してください

import operator
import random

from simple_benchmark import BenchmarkBuilder

b = BenchmarkBuilder()

@b.add_function()
def kederrack_unpacking(l):
    return [f for f, *_ in l]


@b.add_function()
def rakesh_by_index(l):
    return [i[0] for i in l]


@b.add_function()
def wayneSan_zip(l):
    return list(list(zip(*l))[0])


@b.add_function()
def bcattle_itemgetter(l):
     return list(map(operator.itemgetter(0), l))


@b.add_arguments('Number of tuples')
def argument_provider():
    for exp in range(2, 21):
        size = 2**exp
        yield size, [tuple(random.choice(range(100)) for _
                     in range(random.choice(range(2, 100)))) for _ in range(size)]

from pylab import rcParams
rcParams['figure.figsize'] = 12, 7

r = b.run()
r.plot()

0

それらはタプルであり、セットではありません。あなたはこれを行うことができます:

l1 = [(1, u'abc'), (2, u'def')]
l2 = [(tup[0],) for tup in l1]
l2
>>> [(1,), (2,)]

2
実際には何が求められているのではない
Mad Physicist

0

タプルをアンパックして、リスト内包表記を使用して最初の要素のみを取得できます。

l = [(1, u'abc'), (2, u'def')]
[f for f, *_ in l]

出力:

[1, 2]

これは、タプルにいくつの要素があっても機能します。

l = [(1, u'abc'), (2, u'def', 2, 4, 5, 6, 7)]
[f for f, *_ in l]

出力:

[1, 2]

0

なぜ誰もnumpyを使用することを提案しなかったのかと思ったのですが、確認したところ理解できました。混合型配列にはおそらく最適ではありません。

これはnumpyの解決策です:

>>> import numpy as np

>>> a = np.asarray([(1, u'abc'), (2, u'def')])
>>> a[:, 0].astype(int).tolist()
[1, 2]
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.