2010-01-27 14 views
5

Myślę, że rozumowanie listowe może mi to dać, ale nie jestem pewien: jakiekolwiek eleganckie rozwiązania w Pythonie (2.6) w ogóle do wybierania unikalnych obiektów na liście i podawania liczby?Czy rozumienie list w Pythonie (najlepiej) jest równoważne z "count (*) ... group by ..." w SQL?

(Zdefiniowałem unikat w mojej definicji obiektu).

Więc w RDBMS-land, coś takiego:

CREATE TABLE x(n NUMBER(1)); 
INSERT INTO x VALUES(1); 
INSERT INTO x VALUES(1); 
INSERT INTO x VALUES(1); 
INSERT INTO x VALUES(2); 

SELECT COUNT(*), n FROM x 
GROUP BY n; 

Co daje:

COUNT(*) n 
========== 
3  1 
1  2 

Więc oto mój odpowiednik lista w Pythonie:

[1,1,1,2] 

I chcę taki sam wynik jak SQL SELECT daje powyżej.

EDIT: Przykład dałem tutaj została uproszczona, ja rzeczywiście przetwarzanie listy zdefiniowanych przez użytkownika obiektowe przypadkach: po prostu dla kompletności I obejmują dodatkowy kod, co potrzebne, aby cała sprawa do pracy:

import hashlib 

def __hash__(self): 
    md5=hashlib.md5() 
    [md5.update(i) for i in self.my_list_of_stuff] 
    return int(md5.hexdigest(),16) 

Potrzebna była metoda __hash__, aby przekonwertować set do pracy (wybrałem pomysł na zrozumienie listy, który działa w 2.6 [pomimo tego, że nauczyłem się, że wiąże się on z nieefektywnością (patrz komentarze) - mój zestaw danych jest wystarczająco mały bo to nie jest problem]). my_list_of_stuff powyżej jest listą (ciągów znaków) w definicji mojego obiektu.

Odpowiedz

11

Lennart Regebro provided a nice one-liner że robi to, co chcesz:

>>> values = [1,1,1,2] 
>>> print [(x,values.count(x)) for x in set(values)] 
[(1, 3), (2, 1)] 

As S.Lott mentions, A defaultdict może zrobić to samo.

+0

ładne ... okrzyki - działa dobrze na mojej instalacji 2.6. – monojohnny

+3

Rozwiązanie defaultdict będzie o wiele lepsze na większych listach "wartości", ponieważ zapętla je tylko raz, zamiast raz i raz dla każdej unikalnej wartości. –

+0

@Thomas: dzięki za dodanie tego. – bernie

6

Niełatwo jest to zrobić, jak rozumienie list.

from collections import defaultdict 
def group_by(someList): 
    counts = defaultdict(int) 
    for value in someList: 
     counts[value.aKey] += 1 
    return counts 

To bardzo rozwiązanie Python. Ale nie rozumienia listy.

+0

Ta metoda działa, nawet jeśli w ogóle nie jest rozumieniem listy. – Broam

+0

Bardzo dobre rozwiązanie "awk"! mały problem podczas uruchamiania go na moim systemie: ... liczy = defaultdict (int) NameError: globalna nazwa 'defaultdict' nie jest zdefiniowane ... (Python 2.6.2 (r262: 71605, 14 kwietnia 2009, 22:40:02) [MSC v.1500 32 bit (Intel)] na win32) – monojohnny

+2

@monojohnny: '>>> ze zbiorów import defaultdict' – SilentGhost

11
>>> from collections import Counter 
>>> Counter([1,1,1,2]) 
Counter({1: 3, 2: 1}) 

Counter dostępne tylko w py3.1, dziedziczy z dict.

+0

Dlaczego upadek? – SilentGhost

4

Można użyć groupby z modułu itertools:

Make an iterator that returns consecutive keys and groups from the iterable. The key is a function computing a key value for each element. If not specified or is None, key defaults to an identity function and returns the element unchanged. Generally, the iterable needs to already be sorted on the same key function.

>>> a = [1,1,1,2] 
>>> [(len(list(v)), key) for (key, v) in itertools.groupby(sorted(a))] 
[(3, 1), (1, 2)] 

Przypuszczam jego czas pracy jest gorsza niż dict opartych o rozwiązania przez SilentGhost lub S.Lott ponieważ ma do sortowania sekwencji wejściowej , ale powinieneś sam to zrobić. Jest to jednak zrozumienie listy. Powinno być szybsze niż rozwiązanie Adama Berniera, ponieważ nie musi wykonywać powtarzających się skanów liniowych sekwencji wejściowej. W razie potrzeby można uniknąć wywołania sorted przez sortowanie sekwencji wejściowej w linii.

+0

+1 za wysiłek i zgadzam się, że albo rozwiązania S.Lott, albo SilentGhost są lepsze. – bernie

+0

Nie zgadzam się, zanim je wyprofilujesz;) –

+0

dobry punkt :-) W celu wyjaśnienia, zgadzam się na podstawie faktu, że są to wbudowane rozwiązania; już przetestowane i debugowane dla nas. – bernie

1

Następujące prace w Pythonie 2.4 i powinny zatem działać w Pythonie 2 pod numerem.6:

lst = [1,1,2,2,3,4,5,6,5] 
lst_tmp = [] 
lst_dups = [] 

for item in lst: 
    if item in lst_tmp: 
     lst_dups.append(item) 
    else: 
     lst_tmp.append(item) 

if len(lst_dups): 
    lst_dups = sorted(set(lst_dups)) 
    for item in lst_dups: 
     print str(lst.count(item)), "instances of", item 
else: 
    print "list is unique"