2013-04-16 21 views
6

Mam listę list tak:minimum listy list

[[10564, 15], [10564, 13], [10589, 18], [10637, 39], [10662, 38], [10712, 50], [10737, 15], [10762, 14], [10787, 9], [10812, 12], [10837, 45], [3, 17], [7, 21], [46, 26], [48, 12], [49, 24], [64, 14], [66, 
17], [976, 27], [981, 22], [982, 22], [983, 17], [985, 13], [517, 9], [521, 15], [525, 11], [526, 13], [528, 14], [698, 14], [788, 24], [792, 19]] 

Próbuję znaleźć najmniejszą wartość dla drugiego elementu każdej listy (tak porównać 15 do 13 do 18 itd nie porównując 10564 i 15), ale także, aby podzielić je na zakresy, więc mógłbym powiedzieć, najniższy drugi element [1] na każdej liście, tylko jeśli element [0] ma ponad 10000 itd. Jak mogę to zrobić? Próbowałem go i mogę porównywać tylko elementy z tej samej listy co jeszcze, a tego nie chcę. W przypadku, o którym wspomnę, chciałbym wrócić [10787, 9], ale jeśli byłaby inna wartość ponad 10000 z 9, chciałbym też zwrócić to samo.

Odpowiedz

9

To zależy od tego, co chcesz wydrukować. Po pierwsze, trzeba filtrować listę na podstawie „zakresach”

gen = (x for x in lists if x[0] > 10000) 

Warunkiem if może być tak skomplikowane, jak chcesz (w promieniu poprawnej składni). np .:

gen = (x for x in lists if 5000 < x[0] < 10000) 

Jest całkowicie w porządku.


Teraz, jeśli chcesz tylko drugi element z podlist:

min(x[1] for x in gen) 

oczywiście można wbudować całość:

min(x[1] for x in lists if x[0] > 10000) 

Jeśli chcesz całą podmenu :

from operator import itemgetter 
min(gen,key=itemgetter(1)) 

przykład:

>>> lists = [[10564, 15], [10564, 13], [10589, 18], [10637, 39], [10662, 38], [10712, 50], [10737, 15], [10762, 14], [10787, 9], [10812, 12], [10837, 45], [3, 17], [7, 21], [46, 26], [48, 12], [49, 24], [64, 14], [66,17], [976, 27], [981, 22], [982, 22], [983, 17], [985, 13], [517, 9], [521, 15], [525, 11], [526, 13], [528, 14], [698, 14], [788, 24], [792, 19]] 
>>> gen = (x for x in lists if x[0] > 10000) 
>>> min(x[1] for x in gen) 
9 
>>> gen = (x for x in lists if x[0] > 10000) 
>>> from operator import itemgetter 
>>> min(gen,key=itemgetter(1)) 
[10787, 9] 

Niestety, to tylko daje pierwszy podmenu, które odpowiada kryteriom. Aby uzyskać wszystkie z nich:

target = min(x[1] for x in lists if x[0] > 10000) 
matches = [x for x in lists if (x[1] == target) and (x[0] > 10000)] 

Jeśli wiesz na pewno, że nie będzie mniej niż N mecze, można bardziej efektywnie zrobić to trochę z heapq i itertools.takewhile. W ogólnym przypadku, gdy nie znasz górnego limitu liczby dopasowań, myślę, że to rozwiązanie jest lepsze (to O (N) w porównaniu do sortowania, które jest O (NlogN)).


Zauważ, że „generatora wyrażenie” może należy powtórzyć tylko na jeden raz, zanim zostanie wyczerpany

+0

Świetna odpowiedź. Tak, chcę powrócić [10787, 9] Będę czytać itemgetter. Nie rozumiem, co masz na myśli, mówiąc, że wyładowanie generatora jest wyczerpane. Że nie mogę go powtórzyć z jakiegoś powodu? – Paul

+0

@Paul - Dokładnie. Generator można powtórzyć tylko raz. Zwykle nie stanowi to problemu (zawsze możesz stworzyć inny). Jeśli jednak jest to problem, możesz zamiast tego użyć funkcji sprawdzania list: lst = [x dla x na listach, jeśli x [0]> 10000] ' – mgilson

+0

Ah Widzę, idealnie. Dzięki. Bardziej zaznajomieni ze zrozumieniem listy. Nie widzę żadnej różnicy oprócz nawiasów, będę musiał przeczytać różnice z generatorem, dziękuję. – Paul

1
a=[[10564, 15], [10564, 13], [10589, 18], [10637, 39], [10662, 38], [10712, 50], [10737, 15], [10762, 14], [10787, 9], [10812, 12], [10837, 45], [3, 17], [7, 21], [46, 26], [48, 12], [49, 24], [64, 14], [66, 17], [976, 27], [981, 22], [982, 22], [983, 17], [985, 13], [517, 9], [521, 15], [525, 11], [526, 13], [528, 14], [698, 14], [788, 24], [792, 19]] 

print min(map(lambda y: y[1] ,filter(lambda x: x[0]>10000,a))) 
+0

Dzięki, sprawię, że będzie to również droga do zrozumienia. – Paul

2
>>> l=[[10564, 15], [10564, 13], [10589, 18], [10637, 39]] 
>>> min(x[1] for x in l if x[0] > 10000) 
13 
>>> 

aktualizacji dla Twojego komentarza (można użyć lambda dla klucza w min funkcji , itemgetter trochę szybciej na dużych listach):

>>> min((x for x in l if x[0] > 10000), key=lambda k:k[1]) 
[10564, 13] 
+0

Dzięki miło i prosto, chcę zwrócić [10564, 13] w tym przypadku. – Paul

+0

To byłoby moje ulubione, z wyjątkiem tego, że jeśli żaden z 'x [0]> 10000' hold, otrzymasz' ValueError: min() arg jest pustą sekwencją'. Więc musisz zawinąć to w blok 'try: - except ', chyba że znajdziesz sposób na wkradanie się w wartość wartownika dla' min' (nie wydaje mi się, że to jest łatwe) –

+0

@Paul Aby to zrobić koduj więcej samokomponowania, rozważ rozpakowanie 'x [0]' i 'x [1]' i nadaj im opisowe nazwy, takie jak te, gdzie po prostu zgaduję, co 'x [0]' i 'x [1]' może być: 'min (id dla wyniku, id w l, jeśli wynik> 10000)'. –

4

Oto bardzo proste podejście, które j ustuje minimalną wartość, a następnie buduje listę na podstawie tej wartości.

>>> a = [[10564, 15], [10564, 13], [10589, 18], [10637, 39], [10662, 38], [10712, 50], [10737, 15], [10762, 14], [10787, 9], [10812, 12], [10837, 45], [3, 17], [7, 21], [46, 26], [48, 12], [49, 24], [64, 14], [66, 
... 17], [976, 27], [981, 22], [982, 22], [983, 17], [985, 13], [517, 9], [521, 15], [525, 11], [526, 13], [528, 14], [698, 14], [788, 24], [792, 19]] 
>>> a_min = min(i[1] for i in a) 
>>> [i[0] for i in a if i[1] == a_min and i[0] > 10000] + [a_min] 
[10787, 9] 

Kod poprawnie wyświetla wiele wartości:

>>> a += [[10391, 9]] #add another pair with a first value > 10000 
>>> [i[0] for i in a if i[1] == a_min and i[0] > 10000] + [a_min] 
[10787, 10391, 9] 
+0

Bardzo miło, podoba mi się ta mała lista wszystkich możliwych równych wartości! – Paul

+0

Myślę, że wolałbym napisać 'a.append (lst)' niż 'a + = [lst]' – mgilson

+0

Ponadto, dlaczego: '[i [0] dla i w a jeśli i [1] == a_min i ja [ 0]> 10000] + [a_min] 'zamiast:' [i for i in a if i [1] == a_min i i [0]> 10000] ' – mgilson

2

jeśli wymagają wielu min s, to może jesteś najlepszym filtrowania stosowanych elementów i ich sortowania ...

vals = sorted((el for el in your_list if el[0] >= 10000), key=lambda L: L[1]) 
# [[10787, 9], [10812, 12], [10564, 13], [10762, 14], [10564, 15], [10737, 15], [10589, 18], [10662, 38], [10637, 39], [10837, 45], [10712, 50]] 

Następnie można wziąć vals[0], aby uzyskać pierwszą, vals[1], aby uzyskać drugą, lub użyć cięcia, takiego jak vals[:5]. ..

+0

Żałuję, że nie istnieje metoda" Counter.least_common " ... – mgilson

+0

Tutaj możesz nawet użyć 'itertools.takewhile', aby pobrać' L', gdzie 'L [1] == vals [0] [1]' – mgilson