Wie bekomme ich das erste Element in einer Liste von Tupeln?

176

Ich habe eine Liste wie unten, in der das erste Element die ID und das andere eine Zeichenfolge ist:

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

Ich möchte eine Liste von IDs nur aus dieser Liste von Tupeln wie folgt erstellen:

[1,2]

Ich werde diese Liste verwenden, __indaher muss es sich um eine Liste ganzzahliger Werte handeln.

Wasimbhalli
quelle

Antworten:

242
>>> a = [(1, u'abc'), (2, u'def')]
>>> [i[0] for i in a]
[1, 2]
Rakesh
quelle
67

Verwenden Sie die Zip-Funktion, um Elemente zu entkoppeln:

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

Bearbeiten (@BradSolomon): Das Obige funktioniert für Python 2.x, wo zipeine Liste zurückgegeben wird.

Gibt in Python 3.x zipeinen Iterator zurück und Folgendes entspricht dem oben Gesagten:

>>> print(list(list(zip(*inpt))[0]))
[1, 2]
WayneSan
quelle
Benötigt dies einen separaten Import?
JuliandotNut
2
@JuliandotNut Nein, es ist eine eingebaute Funktion. (in Python 2.x)
WayneSan
22

meinst du so etwas

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

Was Sie tatsächlich haben, ist eine Liste von tupleObjekten, keine Liste von Mengen (wie Ihre ursprüngliche Frage impliziert). Wenn es sich tatsächlich um eine Liste von Mengen handelt, gibt es kein erstes Element, da Mengen keine Reihenfolge haben.

Hier habe ich eine flache Liste erstellt, da dies im Allgemeinen nützlicher erscheint als das Erstellen einer Liste mit 1 Element-Tupeln. Sie können jedoch leicht eine Liste von 1 Elemente Tupeln von nur Ersatz schaffen seq[0]mit (seq[0],).

mgilson
quelle
Ich versuchte es. Es gibt diesen Fehler:int() argument must be a string or a number, not 'QuerySet'
Wasimbhalli
4
@wasimbhalli - int()ist nirgends in meiner Lösung, daher muss die Ausnahme, die Sie sehen, später im Code erscheinen.
mgilson
Ich habe die Frage aktualisiert, ich muss diese Liste später __inzum Filtern von Daten verwenden
wasimbhalli
was ist __in? - Basierend auf der von Ihnen angegebenen Beispieleingabe wird eine Liste von Ganzzahlen erstellt. Wenn Ihre Liste der Tupel jedoch nicht mit Ganzzahlen beginnt, erhalten Sie keine Ganzzahlen, und Sie müssen diese über Ganzzahlen interstellen oder versuchen, herauszufinden, warum Ihr erstes Element nicht in eine Ganzzahl konvertiert werden kann.
mgilson
Funktioniert new_list = [ seq[0] for seq in yourlist if type(seq[0]) == int]?
pR0Ps
11

Sie können "Tupel entpacken" verwenden:

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

Zur Iterationszeit wird jedes Tupel entpackt und seine Werte werden auf die Variablen idxund gesetzt val.

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

Dafür ist da operator.itemgetter.

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

Die itemgetterAnweisung gibt eine Funktion zurück, die den Index des von Ihnen angegebenen Elements zurückgibt. Es ist genau das gleiche wie beim Schreiben

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

Aber ich finde das itemgetterklarer und deutlicher .

Dies ist praktisch, um kompakte Sortieranweisungen zu erstellen. Beispielsweise,

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

Aus Sicht der Leistung in python3.X

  • [i[0] for i in a] und list(zip(*a))[0] sind gleichwertig
  • Sie sind schneller als list(map(operator.itemgetter(0), a))

Code

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)

Ausgabe

3.491014136001468e-05

3.422205176000717e-05

Fett gedruckt
quelle
6

Wenn die Tupel eindeutig sind, kann dies funktionieren

>>> 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']
>>> 
Jiri Semmler
quelle
4
Dadurch geht die Bestellung verloren. Es kann jedoch funktionieren ordereddict.
Tim Tisdall
Wenn 2 oder mehr Tupel das gleiche erste Element haben, funktioniert Ihre Lösung nicht
Kederrac
3

als ich lief (wie oben vorgeschlagen):

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

anstatt zurückzukehren:

[1, 2]

Ich erhielt dies als Rückgabe:

<map at 0xb387eb8>

Ich stellte fest, dass ich list () verwenden musste:

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

um eine Liste mit diesem Vorschlag erfolgreich zurückzugeben. Trotzdem bin ich mit dieser Lösung zufrieden, danke. (getestet / ausgeführt mit Spyder, iPython-Konsole, Python v3.6)

James
quelle
3

Ich dachte, dass es nützlich sein könnte, die Laufzeiten der verschiedenen Ansätze zu vergleichen, also habe ich einen Benchmark erstellt (mit simple_benchmark Bibliothek).

I) Benchmark mit Tupeln mit 2 Elementen Geben Sie hier die Bildbeschreibung ein

Wie Sie vielleicht erwarten können, ist die Auswahl des ersten Elements aus Tupeln nach Index 0die schnellste Lösung, die der Entpackungslösung sehr nahe kommt, indem genau 2 Werte erwartet werden

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) Benchmark mit Tupeln mit 2 oder mehr Elementen Geben Sie hier die Bildbeschreibung ein

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()
Kederrac
quelle
0

Das sind Tupel, keine Mengen. Du kannst das:

l1 = [(1, u'abc'), (2, u'def')]
l2 = [(tup[0],) for tup in l1]
l2
>>> [(1,), (2,)]
Lanaru
quelle
2
Nicht wirklich, was gefragt wird
Mad Physicist
0

Sie können Ihre Tupel auspacken und nur das erste Element mit einem Listenverständnis erhalten:

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

Ausgabe:

[1, 2]

Dies funktioniert unabhängig von der Anzahl der Elemente in einem Tupel:

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

Ausgabe:

[1, 2]
Kederrac
quelle
0

Ich fragte mich, warum niemand vorgeschlagen hatte, Numpy zu verwenden, aber jetzt, nachdem ich es überprüft hatte, verstehe ich. Es ist möglicherweise nicht das Beste für Arrays vom gemischten Typ.

Dies wäre eine Lösung in numpy:

>>> import numpy as np

>>> a = np.asarray([(1, u'abc'), (2, u'def')])
>>> a[:, 0].astype(int).tolist()
[1, 2]
CodePrinz
quelle