Załóżmy, że mam zestaw par danych, w którym indeks 0 to wartość, a indeks 1 to typ:
input = [
('11013331', 'KAT'),
('9085267', 'NOT'),
('5238761', 'ETH'),
('5349618', 'ETH'),
('11788544', 'NOT'),
('962142', 'ETH'),
('7795297', 'ETH'),
('7341464', 'ETH'),
('9843236', 'KAT'),
('5594916', 'ETH'),
('1550003', 'ETH')
]
Chcę pogrupować je według ich typu (według pierwszego zindeksowanego ciągu) jako takie:
result = [
{
type:'KAT',
items: ['11013331', '9843236']
},
{
type:'NOT',
items: ['9085267', '11788544']
},
{
type:'ETH',
items: ['5238761', '962142', '7795297', '7341464', '5594916', '1550003']
}
]
Jak mogę to osiągnąć w efektywny sposób?
[('11013331', 'red', 'KAT'), ('9085267', 'blue' 'KAT')]
gdzie ostatni element krotki to klucz, a pierwsze dwie jako wartość. Wynik powinien wyglądać następująco: wynik = [{typ: 'KAT', elementy: [('11013331', czerwony), ('9085267', niebieski)]}]from operator import itemgetter
d= {}; for k,v in input: d.setdefault(k, []).append(v)
Wbudowany
itertools
moduł Pythona w rzeczywistości magroupby
funkcję, ale w tym celu elementy do zgrupowania muszą najpierw zostać posortowane w taki sposób, aby elementy do zgrupowania były ciągłe na liście:Teraz dane wejściowe wyglądają następująco:
groupby
zwraca sekwencję 2-krotek postaci(key, values_iterator)
. Chcemy przekształcić to w listę dykt, w których „typ” jest kluczem, a „pozycje” jest listą zerowych elementów krotek zwracanych przez wartość_iterator. Lubię to:Teraz
result
zawiera żądany dykt, zgodnie z pytaniem.Możesz jednak rozważyć po prostu zrobienie z tego pojedynczego dyktu, kluczowanego według typu i każdej wartości zawierającej listę wartości. W obecnym formularzu, aby znaleźć wartości dla określonego typu, będziesz musiał iterować po liście, aby znaleźć dict zawierający pasujący klucz „type”, a następnie pobrać z niego element „items”. Jeśli używasz pojedynczego dyktowania zamiast listy jednopozycyjnych dykt, możesz znaleźć pozycje dla określonego typu za pomocą pojedynczego klucza wyszukiwania w głównym dyktowaniu. Używając
groupby
, wyglądałoby to następująco:result
zawiera teraz ten dykt (jest podobny do pośredniegores
domyślnego słowa w odpowiedzi @ KennyTM):(Jeśli chcesz zredukować to do jednej linijki, możesz:
lub korzystając z nowomodnego formularza ze zrozumieniem:
źródło
Podobało mi się też proste grupowanie pand . jest potężny, prosty i najbardziej odpowiedni dla dużych zbiorów danych
result = pandas.DataFrame(input).groupby(1).groups
źródło
Ta odpowiedź jest podobna do odpowiedzi @ PaulMcG, ale nie wymaga sortowania danych wejściowych.
Dla tych, którzy zajmują się programowaniem funkcjonalnym,
groupBy
można je zapisać w jednej linii (bez importu!) Iw przeciwieństwie doitertools.groupby
tego nie wymaga sortowania danych wejściowych:(Powodem
... or grp
wlambda
to, że przez toreduce()
do pracy,lambda
potrzeby, aby powrócić swój pierwszy argument, ponieważlist.append()
zawsze zwraca zawsze powrócić . Ie to hack obejść ograniczenie Pythona że lambda może jedynie ocenić jeden wyraz).None
or
grp
Zwraca to dict, którego klucze zostały znalezione przez ocenę danej funkcji i którego wartości są listą oryginalnych elementów w pierwotnej kolejności. Na przykład OP, wywołanie this as
groupBy(lambda pair: pair[1], input)
zwróci ten dykt:I jak na użytkownika @ PaulMcG odpowiedź wymaganym formacie PO można znaleźć poprzez owinięcie że na liście zrozumieniem. Więc to zrobi:
źródło
Następująca funkcja szybko ( bez sortowania ) grupuje krotki o dowolnej długości według klucza mającego dowolny indeks:
W przypadku twojego pytania indeks klucza, według którego chcesz pogrupować, to 1, dlatego:
daje
co nie jest dokładnie tym, o co prosiłeś, ale równie dobrze może odpowiadać Twoim potrzebom.
źródło
źródło