Jak zdobyć pierwszy element z listy krotek?

178

Mam listę jak poniżej, gdzie pierwszy element to id, a drugi to ciąg:

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

Chcę utworzyć listę identyfikatorów tylko z tej listy krotek, jak poniżej:

[1,2]

Użyję tej listy w programie, __inwięc musi to być lista wartości całkowitych.

wasimbhalli
źródło

Odpowiedzi:

245
>>> a = [(1, u'abc'), (2, u'def')]
>>> [i[0] for i in a]
[1, 2]
Rakesh
źródło
68

Użyj funkcji zip, aby oddzielić elementy:

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

Edycja (@BradSolomon): Powyższe działa dla Pythona 2.x, gdzie zipzwraca listę.

W Pythonie 3.x zipzwraca iterator, a następujący jest odpowiednikiem powyższego:

>>> print(list(list(zip(*inpt))[0]))
[1, 2]
WayneSan
źródło
czy to wymaga osobnego importu?
JuliandotNut
2
@JuliandotNut Nie, to funkcja wbudowana. (w Pythonie 2.x)
WayneSan
22

masz na myśli coś takiego?

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

To, co faktycznie masz, to lista tupleobiektów, a nie lista zestawów (jak sugerowało twoje pierwotne pytanie). Jeśli w rzeczywistości jest to lista zbiorów, to nie ma pierwszego elementu, ponieważ zbiory nie mają porządku.

Tutaj utworzyłem płaską listę, ponieważ ogólnie wydaje się to bardziej przydatne niż tworzenie listy krotek 1 elementu. Jednakże, można łatwo utworzyć listę 1 pozycja krotki tylko o wymianie seq[0]z (seq[0],).

mgilson
źródło
Próbowałem tego. Daje ten błąd:int() argument must be a string or a number, not 'QuerySet'
wasimbhalli
4
@wasimbhalli - int()nigdzie nie ma w moim rozwiązaniu, więc wyjątek, który widzisz, musi pojawić się później w kodzie.
mgilson
Zaktualizowałem pytanie, muszę później użyć tej listy __indo filtrowania danych
wasimbhalli
co jest __in? - Na podstawie podanych przykładowych danych wejściowych zostanie utworzona lista liczb całkowitych. Jeśli jednak lista krotek nie zaczyna się od liczb całkowitych, nie otrzymasz liczb całkowitych i będziesz musiał uczynić je liczbami całkowitymi przez intlub spróbować dowiedzieć się, dlaczego pierwszego elementu nie można przekonwertować na liczbę całkowitą.
mgilson
Działa new_list = [ seq[0] for seq in yourlist if type(seq[0]) == int]?
pR0Ps
11

Możesz użyć „rozpakowywania krotek”:

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

W czasie iteracji każda krotka jest rozpakowywana, a jej wartości są ustawiane na zmienne idxi val.

>>> x = (1, u'abc')
>>> idx, val = x
>>> idx
1
>>> val
u'abc'
ssoler
źródło
8

Po to operator.itemgetterjest.

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

itemgetterOświadczenie zwraca funkcję , która zwraca indeks elementu można określić. To dokładnie to samo, co pisanie

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

Ale uważam, że itemgetterjest to jaśniejsze i wyraźniejsze .

Jest to przydatne do tworzenia zwartych instrukcji sortowania. Na przykład,

>>> c = sorted(a, key=operator.itemgetter(0), reverse=True)
>>> c
[(2, u'def'), (1, u'abc')]
bydło
źródło
7

Z punktu widzenia wydajności w python3.X

  • [i[0] for i in a] i list(zip(*a))[0] są równoważne
  • są szybsze niż list(map(operator.itemgetter(0), a))

Kod

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)

wynik

3.491014136001468e-05

3.422205176000717e-05

pogrubienie
źródło
6

jeśli krotki są unikalne, to może działać

>>> 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
źródło
4
Spowoduje to utratę zamówienia. Może to jednak zadziałać ordereddict.
Tim Tisdall
jeśli 2 lub więcej krotek ma ten sam pierwszy element, to rozwiązanie nie zadziała
kederrac
3

kiedy biegałem (jak sugerowałem powyżej):

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

zamiast wracać:

[1, 2]

Otrzymałem jako zwrot:

<map at 0xb387eb8>

Okazało się, że muszę użyć list ():

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

aby pomyślnie zwrócić listę, korzystając z tej sugestii. To powiedziawszy, jestem zadowolony z tego rozwiązania, dzięki. (przetestowane / uruchomione przy użyciu Spyder, konsoli iPython, Python v3.6)

James
źródło
3

Pomyślałem, że może być przydatne porównanie środowisk wykonawczych różnych podejść, więc zrobiłem test porównawczy (używając simple_benchmark biblioteki )

I) Benchmark mający krotki z 2 elementami wprowadź opis obrazu tutaj

Jak można się spodziewać, że wybór pierwszego elementu z krotek według indeksu 0jest najszybszym rozwiązaniem bardzo zbliżonym do rozwiązania do rozpakowywania, oczekując dokładnie 2 wartości

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 mający krotki z 2 lub więcej elementami wprowadź opis obrazu tutaj

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
źródło
0

To są krotki, a nie zestawy. Możesz to zrobić:

l1 = [(1, u'abc'), (2, u'def')]
l2 = [(tup[0],) for tup in l1]
l2
>>> [(1,), (2,)]
Lanaru
źródło
2
Nie bardzo, o co się pytają
Mad Physicist,
0

możesz rozpakować swoje krotki i uzyskać tylko pierwszy element, używając rozumienia list:

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

wynik:

[1, 2]

to zadziała bez względu na to, ile elementów masz w krotce:

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

wynik:

[1, 2]
kederrac
źródło
0

Zastanawiałem się, dlaczego nikt nie zasugerował użycia numpy, ale teraz po sprawdzeniu rozumiem. Może nie jest najlepszy dla tablic typu mieszanego.

To byłoby rozwiązanie w numpy:

>>> import numpy as np

>>> a = np.asarray([(1, u'abc'), (2, u'def')])
>>> a[:, 0].astype(int).tolist()
[1, 2]
CodePrinz
źródło