2010-11-06 19 views
9

Załóżmy, że mam listę krotek:Python: warunkowo usuwać elementy z listy

x = [(1,2), (3,4), (7,4), (5,4)] 

Spośród wszystkich krotek, które dzielą drugi element, chcę zachować krotki z największą pierwszego elementu:

y = [(1,2), (7,4)] 

Jaki jest najlepszy sposób na osiągnięcie tego w Pythonie?


Dzięki za odpowiedzi.

  • Krotki mogą być zamiast tego listami dwuelementowymi, jeśli to robi różnicę.
  • Wszystkie elementy są nieujemnymi liczbami całkowitymi.
  • Podoba mi się bieżące odpowiedzi. Naprawdę powinienem dowiedzieć się więcej o tym, co ma do zaoferowania collections!
+0

Czy zachowujesz kolejność krotek; to znaczy, jeśli oryginał to '[(a, b), (x, y)]', to wynik musi mieć '[(a, b), (x, y)]' jako kolejność, lub jest ' [(x, y), (a, b)] "dopuszczalne? Czy zachowujesz kolejność liczb całkowitych w krotkach; to znaczy, że "[(b, a), (y, x)]" jest dopuszczalne? – gotgenes

+0

Zamówienie wewnątrz krotek należy zachować. Kolejność krotek na liście powinna być zachowana, ale można je łatwo sortować za pomocą 'y.sort()', która będzie działać na pierwszym elemencie każdej krotki. –

+1

@Steve Wierzę, że twoje twierdzenie, że kolejność pojawiania się krotek na liście jest zachowana, zaprzecza deklarowaniu, że mogą być również sortowane za pomocą 'sort()', chyba że w twoim pytaniu znajduje się nie sformułowane założenie, że lista wejściowa jest posortowana według pierwszy element krotek. – gotgenes

Odpowiedz

5

podobne do odpowiedzi Aarona

>>> from collections import defaultdict 
>>> x = [(1,2), (3,4), (7,4), (5,4)] 
>>> d = defaultdict(int) 
>>> for v,k in x: 
... d[k] = max(d[k],v) 
... 
>>> y=[(k,v) for v,k in d.items()] 
>>> y 
[(1, 2), (7, 4)] 

Zauważ, że kolejność nie jest zachowana przy użyciu tej metody. Aby zachować zamówienie, użyj tego zamiast tego w inny sposób. Używa więcej pamięci, ale ma mniej połączeń na max, więc może to być szybciej

>>> d = defaultdict(list) 
>>> for k,v in x: 
... d[v].append(k) 
... 
>>> y = [(max(k),v) for v,k in d.items()] 
>>> y 
[(1, 2), (7, 4)] 

Znowu proste modyfikacje zachowuje kolejność

>>> y = [(k,v) for k,v in x if max(d[v])==k] 
>>> y 
[(1, 2), (7, 4)] 
+0

+1. Twoja poprawa mojej odpowiedzi jest bardzo miła. – aaronasterling

5

użycie collections.defaultdict

import collections 

max_elements = collections.defaultdict(tuple) 

for item in x: 
    if item > max_elements[item[1]]: 
     max_elements[item[1]] = item 

y = max_elements.values() 
+0

Dziękuję za odpowiedź. Już majstrowałem przy twojej wcześniejszej odpowiedzi, która zadziałała w moim przypadku. Czy mogę zapytać, dlaczego to zmieniłeś? –

+0

@Steve, to jest wykonywane tylko raz i będzie zużywać znacznie mniej pamięci na większą listę. W sumie jest znacznie lepiej. – aaronasterling

+1

Dzięki. Chciałbym przegłosować, ale TAK blokuje mnie, ponieważ przegłosowałem, a następnie anulowałem (zanim mogłem w pełni zrozumieć odpowiedź), wtedy pomyślałem, że mogę ponownie przegłosować. –

0

Moje własne próby, lekko inspirowany aaronsterling:

(oh yeah, wszystkie elementy są nieujemne)

def processtuples(x): 
    d = {} 
    for item in x: 
     if x[0] > d.get(x[1],-1): 
      d[x[1]] = x[0] 

    y = [] 
    for k in d: 
     y.append((d[k],k)) 
    y.sort() 
    return y 
0
>>> from collections import defaultdict 
>>> d = defaultdict(tuple) 
>>> x = [(1,2), (3,4), (7,4), (5,4)] 
>>> for a, b in x: 
...  d[b] = max(d[b], (a, b)) 
... 
>>> d.values() 
[(1, 2), (7, 4) 
2

Jeśli można zrobić założenie, że krotki z identyczne drugie elementy pojawiają się w ciągłej kolejności na pierwotnej liście x można wykorzystać itertools.groupby:

import itertools 
import operator 

def max_first_elem(x): 
    groups = itertools.groupby(x, operator.itemgetter(1)) 
    y = [max(g[1]) for g in groups] 
    return y 

pamiętać, że to gwarantuje zachowanie kolejności grup (przez drugi element krotki), jeśli jest to pożądane ograniczenie dla wyjścia.

Powiązane problemy