Hoe een woordenboek filteren volgens een willekeurige voorwaardefunctie?

Ik heb een woordenboek van punten, zeg:

>>> points={'a':(3,4), 'b':(1,2), 'c':(5,5), 'd':(3,3)}

Ik wil een nieuw woordenboek maken met alle punten waarvan de x- en y-waarde kleiner is dan 5, d.w.z. de punten ‘a’, ‘b’ en ‘d’.

Volgens de het boekheeft elk woordenboek de Functie items(), die een lijst met (key, pair)tuple retourneert:

>>> points.items()
[('a', (3, 4)), ('c', (5, 5)), ('b', (1, 2)), ('d', (3, 3))]

Dus ik heb dit geschreven:

>>> 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)}

Is er een elegantere manier? Ik verwachtte dat Python een super-geweldige dictionary.filter(f)-functie zou hebben…


Antwoord 1, autoriteit 100%

U kunt een dictaatbegrip gebruiken:

{k: v for k, v in points.items() if v[0] < 5 and v[1] < 5}

En in Python 2, vanaf 2.7:

{k: v for k, v in points.iteritems() if v[0] < 5 and v[1] < 5}

Antwoord 2, autoriteit 24%

dict((k, v) for k, v in points.items() if all(x < 5 for x in v))

Je zou ervoor kunnen kiezen om .iteritems()aan te roepen in plaats van .items()als je in Python 2 zit en pointsmogelijk een veelaan inzendingen.

all(x < 5 for x in v)kan overdreven zijn als je zeker weet dat elk punt altijd alleen 2D zal zijn (in dat geval zou je dezelfde beperking kunnen uitdrukken met een and) maar het zal prima werken;-).


Antwoord 3, autoriteit 5%

points_small = dict(filter(lambda (a,(b,c)): b<5 and c < 5, points.items()))

Antwoord 4, autoriteit 4%

>>> 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)}

Antwoord 5, autoriteit 2%

dict((k, v) for (k, v) in points.iteritems() if v[0] < 5 and v[1] < 5)

Antwoord 6, autoriteit 2%

Ik denk dat het antwoord van Alex Martelli absoluut de meest elegante manier is om dit te doen, maar ik wilde gewoon een manier toevoegen om te voldoen aan je behoefte aan een super geweldige dictionary.filter(f)-methode in een Pythonische manier:

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)

In principe creëren we een klasse die erft van dict, maar voegt de filtermethode toe. We moeten wel .items()gebruiken voor het filteren, aangezien het gebruik van .iteritems()terwijl destructief itereren een uitzondering oplevert.


Antwoord 7

dict((k, v) for (k, v) in points.iteritems() if v[0] < 5 and v[1] < 5)

Other episodes