2013-10-01 11 views
5

Mam listę jak tenróżnica między dict (GroupBy) i GroupBy

[u'201003', u'200403', u'200803', u'200503', u'201303', 
u'200903', u'200603', u'201203', u'200303', u'200703', u'201103'] 

Nazwijmy tę listę jako 'years_list'

Kiedy zrobiłem GroupBy roku,

group_by_yrs_list = groupby(years_list, key = lambda year_month: year_month[:-2]) 
for k,v in group_by_yrs_list: 
    print k, list(v) 

I uzyskałem pożądaną moc wyjściową:

2010 [u'201003'] 
2004 [u'200403'] 
2008 [u'200803'] 
2005 [u'200503'] 
2013 [u'201303'] 
2009 [u'200903'] 
2006 [u'200603'] 
2012 [u'201203'] 
2003 [u'200303'] 
2007 [u'200703'] 
2011 [u'201103'] 

Potem lekko zmienił mój realizacja tak,

group_by_yrs_list = dict(groupby(years_list, key = lambda year_month: year_month[:-2])) 
    for k,v in group_by_yrs_list.items(): 
    print k, list(v) 

Właśnie dodał dict, ale wynik jest inny,

2003 [] 
2006 [] 
2007 [] 
2004 [] 
2005 [] 
2008 [] 
2009 [] 
2011 [u'201103'] 
2010 [] 
2013 [] 
2012 [] 

Nie mogłem dowiedzieć się, dlaczego. Proszę, pomóż mi znaleźć to, co faktycznie robi dict.

(Python 2,7)

+0

Pamiętaj, że słowniki nie mają zamówienia. Ale co do tego, dlaczego tylko jedna lista nie jest pusta, to jest dziwne – TerryA

+1

@Haidro: Odpowiedź przez falstru powinna cię oświecić. – justhalf

+0

@justhalf Oh oczywiście! – TerryA

Odpowiedz

8

groupby daje pary (na klucze, iteracyjnej -of grupami). Jeśli wykonujesz iterację drugiej pary, iterator-grupy pierwszej pary jest już zużyty, więc otrzymasz pustą listę.

Spróbuj poniższy kod:

group_by_yrs_list = {year:list(grp) for year, grp in groupby(years_list, key=lambda year_month: year_month[:-2])} 
for k, v in group_by_yrs_list.items(): 
    print k, v 
+1

co oznacza, że ​​wszystkie pogrupowane wartości odnoszą się do pojedynczego iteratora. Mam rację ? –

+3

@JohnPrawyn, Tak. ['itertools._grouper'] (http://hg.python.org/cpython/file/70850d6a16ee/Modules/itertoolsmodule.c#l197) obiekty współdzielą jeden iterator. ('gbo-> it') – falsetru

1

Według this answer, można to zrobić, aby przekształcić go w dict:

group_by_yrs_list = dict((k,list(v)) for k,v in groupby(years_list, key=lambda x: x[:4])) 

To dlatego wyjście groupby jest itertools.groupby obiekt, który jest rodzaj generatora, który najwyraźniej nie może być użyty bezpośrednio jako argument dla konstruktora dict.

6

Problem polega na tym, że groupby plony, kolejno, każdy klawisz i sub-iterator:

>>> for k, v in groupby(years_list, key = lambda year_month: year_month[:-2]): 
... print k, v 
2010 <itertools._grouper object at 0x801c68950> 
2004 <itertools._grouper object at 0x801bb3a90> 
2008 <itertools._grouper object at 0x801c68950> 
2005 <itertools._grouper object at 0x801bb3a90> 
2013 <itertools._grouper object at 0x801c68950> 
2009 <itertools._grouper object at 0x801bb3a90> 
2006 <itertools._grouper object at 0x801c68950> 
2012 <itertools._grouper object at 0x801bb3a90> 
2003 <itertools._grouper object at 0x801c68950> 
2007 <itertools._grouper object at 0x801bb3a90> 
2011 <itertools._grouper object at 0x801c68950> 

Musisz włączyć każdy <itertools._grouper object ...> do rzeczywistej listy przed przechowywanie go z dala, bo następnego iteracja groupby resetuje iterator. Jeśli nie, pozostanie tylko jeden użyteczny iterator, więc gdy drukujesz zawartość słownika, dostajesz jedną niepustą listę (która używa iteratora). Drukujesz go po raz drugi, dostaniesz wszystkie puste listy.

Kluczem jest lista-ity iteratorów, gdy są jeszcze dobre (widzę kilka innych pobiło mnie do przykładowego kodu, wolę falsetru's variant).

+2

Od [docs] (http://docs.python.org/2/library/itertools.html#itertools.groupby): Ponieważ źródło jest współdzielone, gdy' groupby() ' obiekt jest zaawansowany, poprzednia grupa ** nie jest już widoczna **. Tak więc, jeśli dane te są potrzebne później, powinny być przechowywane jako lista. –

+0

Tak, w zasadzie to samo zdanie, ale krótsze i bardziej precyzyjne (nie mówię dokładnie * dlaczego * starszy ' stał się bezużyteczny), ale podejrzewam, że wersja może latać nad Głowa OP :-) – torek

+0

Twoja odpowiedź jest wystarczająco jasna, chciałem tylko dodać odniesienie do dokumentów. –

2

Spróbuj non-strumieniowe groupby operację od toolz

$ pip install toolz 
$ ipython 

In [1]: from toolz import groupby 

In [2]: years_list = [u'201003', u'200403', u'200803', u'200503', u'201303', 
    ...: u'200903', u'200603', u'201203', u'200303', u'200703', u'201103'] 

In [3]: get_year = lambda year_month: year_month[:-2] 

In [4]: groupby(get_year, years_list) 
Out[4]: 
{u'2003': [u'200303'], 
u'2004': [u'200403'], 
u'2005': [u'200503'], 
u'2006': [u'200603'], 
u'2007': [u'200703'], 
u'2008': [u'200803'], 
u'2009': [u'200903'], 
u'2010': [u'201003'], 
u'2011': [u'201103'], 
u'2012': [u'201203'], 
u'2013': [u'201303']}