Jak filtrować słownik według dowolnej funkcji warunkowej?
Mam słownik punktów, powiedzmy:
>>> points={'a':(3,4), 'b':(1,2), 'c':(5,5), 'd':(3,3)}
Chcę utworzyć nowy słownik ze wszystkimi punktami, których wartości x i y są mniejsze niż 5, tj. punkty "A", " b " I "d".
Zgodnie z księgą , każdy słownik posiada funkcję items()
, która zwraca listę(key, pair)
krotki:
>>> points.items()
[('a', (3, 4)), ('c', (5, 5)), ('b', (1, 2)), ('d', (3, 3))]
Więc napisałem to:
>>> for item in [i for i in points.items() if i[1][0]<5 and i[1][1]<5]:
... points_small[item[0]]=item[1]
...
>>> points_small
{'a': (3, 4), 'b': (1, 2), 'd': (3, 3)}
Czy jest jakiś bardziej elegancki sposób? Spodziewałem się, że Python będzie miał jakąś super-niesamowitą funkcję dictionary.filter(f)
... 7 answers
Obecnie, w Pythonie 2.7 i nowszych, można użyć rozumienia dict:
{k: v for k, v in points.iteritems() if v[0] < 5 and v[1] < 5}
I w Pythonie 3:
{k: v for k, v in points.items() if v[0] < 5 and v[1] < 5}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-27 12:13:42
dict((k, v) for k, v in points.items() if all(x < 5 for x in v))
Możesz wybrać wywołanie .iteritems()
zamiast .items()
jeśli jesteś w Pythonie 2 i points
może miećlot wpisów.
all(x < 5 for x in v)
może to być przesada, jeśli wiesz na pewno, że każdy punkt będzie zawsze tylko 2D (w takim przypadku możesz wyrazić to samo ograniczenie za pomocą and
), ale będzie działać dobrze; -).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-16 16:37:47
points_small = dict(filter(lambda (a,(b,c)): b<5 and c < 5, points.items()))
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-16 16:35:56
dict((k, v) for (k, v) in points.iteritems() if v[0] < 5 and v[1] < 5)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-16 16:35:19
>>> points = {'a': (3, 4), 'c': (5, 5), 'b': (1, 2), 'd': (3, 3)}
>>> dict(filter(lambda x: (x[1][0], x[1][1]) < (5, 5), points.items()))
{'a': (3, 4), 'b': (1, 2), 'd': (3, 3)}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-11 13:02:23
Myślę, że odpowiedź Alexa Martelli jest zdecydowanie najbardziej eleganckim sposobem, aby to zrobić, ale chciałem tylko dodać sposób, aby zaspokoić swoje pragnienie super awesomedictionary.filter(f)
Metoda w sposób Pythoniczny:
class FilterDict(dict):
def __init__(self, input_dict):
for key, value in input_dict.iteritems():
self[key] = value
def filter(self, criteria):
for key, value in self.items():
if (criteria(value)):
self.pop(key)
my_dict = FilterDict( {'a':(3,4), 'b':(1,2), 'c':(5,5), 'd':(3,3)} )
my_dict.filter(lambda x: x[0] < 5 and x[1] < 5)
Zasadniczo tworzymy klasę, która dziedziczy z dict
, ale dodaje metodę filtrowania. Musimy użyć .items()
do filtrowania, ponieważ użycie .iteritems()
podczas destruktywnej iteracji wywoła wyjątek.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-03 22:23:01
dict((k, v) for (k, v) in points.iteritems() if v[0] < 5 and v[1] < 5)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-16 16:39:17