2016-06-01 11 views
3

Gibt es eine nette pythonische Art, eine Liste in eine Liste von Listen zu gruppieren, wobei jede der inneren Listen nur die Elemente enthält, die die gleiche Projektion haben Benutzer als Funktion?Python: eine Liste in Unterlisten durch eine Gleichheit des projizierten Wertes gruppieren

Beispiel:

>>> x = [0, 1, 2, 3, 4, 5, 6, 7] 
>>> groupby(x, projection=lambda e: e % 3) 
[[0, 3, 6], [1, 4, 7], [2, 5]] 

I kümmern sich nicht um die Projektion selbst, dass nur, wenn es für einige Elemente gleich sind diese in der gleichen sublist enden.

suche ich im Grunde für einen Python-Äquivalent der Haskell Funktion GHC.Exts.groupWith:

Prelude> import GHC.Exts 
Prelude GHC.Exts> groupWith (`mod` 3) [0..7] 
[[0,3,6],[1,4,7],[2,5]] 

Antwort

6

Das itertools Modul im Standard-Bibliothek enthält eine groupby() Funktion, die tun soll, was Sie wollen.

Beachten Sie, dass die Eingabe zu groupby() nach dem Gruppenschlüssel sortiert werden sollte, um jede Gruppe nur einmal zu erhalten, aber es ist einfach, die gleiche Schlüsselfunktion zum Sortieren zu verwenden. Also, wenn Ihre Schlüsselfunktion (Projektion) auf sucht, ob eine Zahl gerade ist, würde es so aussehen:

from itertools import groupby 
x = [0, 1, 2, 3, 4, 5, 6, 7] 

def projection(val): 
    return val % 3 

x_sorted = sorted(x, key=projection) 
x_grouped = [list(it) for k, it in groupby(x_sorted, projection)]  
print(x_grouped) 

[[0, 3, 6], [1, 4, 7], [2, 5]] 

Beachten Sie, dass während dieser Version verwendet nur Standard-Python-Funktionen, wenn Sie mit mehr als vielleicht 100.000 beschäftigen Werte sollten Sie in Pandas suchen (siehe @ Ayhan's Antwort)

4

Keine Notwendigkeit zu sortieren.

from collections import defaultdict 

def groupby(iterable, projection): 
    result = defaultdict(list) 
    for item in iterable: 
     result[projection(item)].append(item) 
    return result 

x = [0, 1, 2, 3, 4, 5, 6, 7] 
groups = groupby(x, projection=lambda e: e % 3) 
print groups 
print groups[0] 

Ausgang:

defaultdict(<type 'list'>, {0: [0, 3, 6], 1: [1, 4, 7], 2: [2, 5]}) 
[0, 3, 6] 
1

Hier wird ein Ansatz compress von itertools:

from itertools import compress 
import numpy as np 

L = [i %3 for i in x] 

[list(compress(x, np.array(L)==i)) for i in set(L)] 
#[[0, 3, 6], [1, 4, 7], [2, 5]] 
+0

'np.array (L)' sollte wahrscheinlich in einer temporären Variable gespeichert werden, so dass es nicht für jeden Schlüssel (Vorhersage) berechnet werden muss. –

2

A pandas Version so sein würde:

import pandas as pd 
x = [0, 1, 2, 3, 4, 5, 6, 7] 
pd.Series(x).groupby(lambda t: t%3).groups 
Out[13]: {0: [0, 3, 6], 1: [1, 4, 7], 2: [2, 5]} 

Oder

pd.Series(x).groupby(lambda t: t%3).groups.values() 
Out[32]: dict_values([[0, 3, 6], [1, 4, 7], [2, 5]])