web-dev-qa-db-fra.com

Compréhension de liste Python pour les dictionnaires dans les dictionnaires?

Je viens d’apprendre la compréhension de liste, qui est un excellent moyen rapide d’obtenir des données dans une seule ligne de code. Mais quelque chose m'embête.

Dans mon test, j'ai ce genre de dictionnaires dans la liste:

[{'y': 72, 'x': 94, 'fname': 'test1420'}, {'y': 72, 'x': 94, 'fname': 'test277'}]

La compréhension de la liste s = [ r for r in list if r['x'] > 92 and r['x'] < 95 and r['y'] > 70 and r['y'] < 75 ] fonctionne parfaitement sur celui-ci (il s’agit en fait du résultat de cette ligne)

Quoi qu'il en soit, j'ai alors réalisé que je n'utilisais pas vraiment une liste dans mon autre projet, mais un dictionnaire. Ainsi:

{'test1420': {'y': '060', 'x': '070', 'fname': 'test1420'}}

De cette façon, je peux simplement éditer mon dictionnaire avec var['test1420'] = ...

Mais la compréhension des listes ne fonctionne pas avec ça! Et je ne peux pas éditer des listes de cette façon parce que vous ne pouvez pas assigner un index comme ça.

Y a-t-il un autre moyen?

21
skerit

Tu peux le faire:

s = dict([ (k,r) for k,r in mydict.iteritems() if r['x'] > 92 and r['x'] < 95 and r['y'] > 70 and r['y'] < 75 ])

Cela prend un dict comme vous l'avez spécifié et retourne un dict 'filtré'.

36
adamk

Si dct est 

{'test1420': {'y': '060', 'x': '070', 'fname': 'test1420'},
 'test277': {'y': 72, 'x': 94, 'fname': 'test277'},}

Peut-être cherchez-vous quelque chose comme:

[ subdct for key,subdct in dct.iteritems() 
  if 92<subdct['x']<95 and 70<subdct['y']<75 ]

Un petit avantage est que Python vous permet de chaîner les inégalités:

92<dct[key]['x']<95

au lieu de

if r['x'] > 92 and r['x'] < 95

Notez également que ci-dessus j'ai écrit une liste de compréhension, donc vous obtenez une liste (dans ce cas, des dicts).

En Python3, il existe des choses telles que dict comprehensions ainsi:

{ n: n*n for n in range(5) } # dict comprehension
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

En Python2, l'équivalent serait 

dict( (n,n*n) for n in range(5) )

Je ne sais pas si vous cherchez une liste de dictés ou un dicton de dictés, mais si vous comprenez les exemples ci-dessus, il est facile de modifier ma réponse pour obtenir ce que vous voulez.

8
unutbu

On dirait que vous voulez quelque chose comme:

my_dict = {'test1420': {'y': '060', 'x': '070', 'fname': 'test1420'},
           'test277' : {'y': '072', 'x': '094', 'fname': 'test277'}}


new_dict = dict((k,v) for k,v in my_dict.items() 
                    if 92 < int(v['x']) < 95 and 70 < int(v['y']) < 75)

Quelques notes sur ce code:

  1. J'utilise une expression génératrice Au lieu d'une liste de compréhension
  2. Python vous permet de combiner les tests d'inégalité En tant que low < value < high 
  3. Le constructeur dict () prend un Itératif de nuplets clé/valeur pour créer un dictionnaire
2
Triptych

Vous pouvez obtenir une liste des valeurs d’un dictionnaire d avec d.values(). Votre compréhension de liste devrait fonctionner avec cela, bien que je sois un peu incertain quant à ce que vous voulez exactement.

0
Rob Lourens

Y a-t-il un autre moyen?

Pourquoi ne pas envisager l'utilisation de certains objets légers? 

Vous pouvez still utiliser des compréhensions de liste pour rassembler ou filtrer les objets, et gagner beaucoup en clarté/extensibilité.

>>> class Item(object):
...     def __init__(self, x, y, name):
...         self.x = x
...         self.y = y
...         self.name = name
... 
>>> list_items = []
>>> list_items.append(Item(x=70, y=60, name='test1420'))                        
>>> list_items.append(Item(x=94, y=72, name='test277'))                         
>>> items_matching = [item for item in list_items 
                      if 92 < item.x < 95 and 70 < item.y < 75]
>>> for item in items_matching:
...     print item.name
... 
test277
>>> first_item = items_matching[0]
>>> first_item.x += 50
>>> first_item.x
144
0
ChristopheD