116 votes

Python: Touples / dictionnaires en tant que clés, sélectionnez, triez

supposons que j'ai quantités de fruits de différentes couleurs, par exemple, 24 bleu bananes, 12 pommes vertes, 0 bleu fraises et ainsi de suite. Je tiens à les organiser dans une structure de données en Python qui permet de simplifier la sélection et le tri. Mon idée était de les mettre dans un dictionnaire avec les tuples comme des clés, par exemple,

{ ('banana',    'blue' ): 24,
  ('apple',     'green'): 12,
  ('strawberry','blue' ): 0,
  ...
}

ou même les dictionnaires, par exemple,

{ {'fruit': 'banana',    'color': 'blue' }: 24,
  {'fruit': 'apple',     'color': 'green'}: 12,
  {'fruit': 'strawberry','color': 'blue' }: 0,
  ...
}

J'aimerais récupérer une liste de tous les bleus de fruits, ou des bananes de toutes les couleurs, par exemple, ou pour le tri de ce dictionnaire par le nom du fruit. Est-il possible de le faire de manière propre?

Il se pourrait bien que les dictionnaires avec les tuples que les clés ne sont pas la bonne façon de gérer cette situation.

Toutes les suggestions sont les bienvenues!

160voto

senderle Points 41607

Personnellement, une des choses que j'aime à propos de python est le n-uplet-dict combinaison. Ce que vous avez ici est effectivement un tableau 2d (où x = fruit nom et y = couleur), et je suis plutôt un partisan de la dict de tuples pour la mise en œuvre de tableaux 2d, au moins, quand quelque chose comme numpy ou base de données n'est pas le plus approprié. Donc en bref, je pense que vous avez une bonne approche.

Notez que vous ne pouvez pas utiliser les dicts comme clés dans un dict sans faire un travail supplémentaire, ce qui n'est pas une très bonne solution.

Cela dit, vous devriez également considérer namedtuple(). De cette façon, vous pourriez faire ceci:

>>> from collections import namedtuple
>>> Fruit = namedtuple("Fruit", ["name", "color"])
>>> f = Fruit(name="banana", color="red")
>>> print f
Fruit(name='banana', color='red')
>>> f.name
'banana'
>>> f.color
'red'

Vous pouvez maintenant utiliser votre fruitcount dict:

>>> fruitcount = {Fruit("banana", "red"):5}
>>> fruitcount[f]
5

Autres astuces:

>>> fruits = fruitcount.keys()
>>> fruits.sort()
>>> print fruits
[Fruit(name='apple', color='green'), 
 Fruit(name='apple', color='red'), 
 Fruit(name='banana', color='blue'), 
 Fruit(name='strawberry', color='blue')]
>>> fruits.sort(key=lambda x:x.color)
>>> print fruits
[Fruit(name='banana', color='blue'), 
 Fruit(name='strawberry', color='blue'), 
 Fruit(name='apple', color='green'), 
 Fruit(name='apple', color='red')]

En écho à chmullig, pour obtenir une liste de toutes les couleurs d'un fruit, vous devez filtrer les clés, c'est à dire

bananas = [fruit for fruit in fruits if fruit.name=='banana']

21voto

Cuga Points 6286

Votre meilleure option sera de créer une simple structure de données pour le modèle de ce que vous avez. Ensuite, vous pouvez stocker ces objets dans une liste simple et de tri/récupération de la façon que vous le souhaitez.

Pour ce cas, j'aimerais utiliser la classe suivante:

class Fruit:
    def __init__(self, name, color, quantity): 
        self.name = name
        self.color = color
        self.quantity = quantity

    def __str__(self):
        return "Name: %s, Color: %s, Quantity: %s" % \
     (self.name, self.color, self.quantity)

Ensuite, vous pouvez simplement construire des "Fruits", les instances et les ajouter à une liste, comme indiqué de la manière suivante:

fruit1 = Fruit("apple", "red", 12)
fruit2 = Fruit("pear", "green", 22)
fruit3 = Fruit("banana", "yellow", 32)
fruits = [fruit3, fruit2, fruit1] 

La simple liste fruits sera beaucoup plus facile, moins confus, et mieux entretenu.

Quelques exemples d'utilisation:

Toutes les sorties ci-dessous est le résultat après l'exécution de la donnée extrait de code de suivi par:

for fruit in fruits:
    print fruit

Liste non triée:

Affiche:

Name: banana, Color: yellow, Quantity: 32
Name: pear, Color: green, Quantity: 22
Name: apple, Color: red, Quantity: 12

Classés par ordre alphabétique par nom:

fruits.sort(key=lambda x: x.name.lower())

Affiche:

Name: apple, Color: red, Quantity: 12
Name: banana, Color: yellow, Quantity: 32
Name: pear, Color: green, Quantity: 22

Triés par la quantité:

fruits.sort(key=lambda x: x.quantity)

Affiche:

Name: apple, Color: red, Quantity: 12
Name: pear, Color: green, Quantity: 22
Name: banana, Color: yellow, Quantity: 32

D'où la couleur == red:

red_fruit = filter(lambda f: f.color == "red", fruits)

Affiche:

Name: apple, Color: red, Quantity: 12

19voto

eyquem Points 9942

La base de données, dict des dicts, dictionnaire de la liste des dictionnaires, nommé n-uplet (c'est une sous-classe), sqlite, redondance... Je n'ai pas en croire mes yeux. Quoi d'autre ?

"Il se pourrait bien que les dictionnaires avec les tuples que les clés ne sont pas la bonne façon de gérer cette situation."

"mon sentiment est qu'une base de données est trop pour l'OP; "

Ouais! J'ai pensé

Donc, à mon avis, une liste de tuples est beaucoup assez :

from operator import itemgetter

li = [  ('banana',     'blue'   , 24) ,
        ('apple',      'green'  , 12) ,
        ('strawberry', 'blue'   , 16 ) ,
        ('banana',     'yellow' , 13) ,
        ('apple',      'gold'   , 3 ) ,
        ('pear',       'yellow' , 10) ,
        ('strawberry', 'orange' , 27) ,
        ('apple',      'blue'   , 21) ,
        ('apple',      'silver' , 0 ) ,
        ('strawberry', 'green'  , 4 ) ,
        ('banana',     'brown'  , 14) ,
        ('strawberry', 'yellow' , 31) ,
        ('apple',      'pink'   , 9 ) ,
        ('strawberry', 'gold'   , 0 ) ,
        ('pear',       'gold'   , 66) ,
        ('apple',      'yellow' , 9 ) ,
        ('pear',       'brown'  , 5 ) ,
        ('strawberry', 'pink'   , 8 ) ,
        ('apple',      'purple' , 7 ) ,
        ('pear',       'blue'   , 51) ,
        ('chesnut',    'yellow',  0 )   ]


print set( u[1] for u in li ),': all potential colors'
print set( c for f,c,n in li if n!=0),': all effective colors'
print [ c for f,c,n in li if f=='banana' ],': all potential colors of bananas'
print [ c for f,c,n in li if f=='banana' and n!=0],': all effective colors of bananas'
print

print set( u[0] for u in li ),': all potential fruits'
print set( f for f,c,n in li if n!=0),': all effective fruits'
print [ f for f,c,n in li if c=='yellow' ],': all potential fruits being yellow'
print [ f for f,c,n in li if c=='yellow' and n!=0],': all effective fruits being yellow'
print

print len(set( u[1] for u in li )),': number of all potential colors'
print len(set(c for f,c,n in li if n!=0)),': number of all effective colors'
print len( [c for f,c,n in li if f=='strawberry']),': number of potential colors of strawberry'
print len( [c for f,c,n in li if f=='strawberry' and n!=0]),': number of effective colors of strawberry'
print

# sorting li by name of fruit
print sorted(li),'  sorted li by name of fruit'
print

# sorting li by number 
print sorted(li, key = itemgetter(2)),'  sorted li by number'
print

# sorting li first by name of color and secondly by name of fruit
print sorted(li, key = itemgetter(1,0)),'  sorted li first by name of color and secondly by name of fruit'
print

résultat

set(['blue', 'brown', 'gold', 'purple', 'yellow', 'pink', 'green', 'orange', 'silver']) : all potential colors
set(['blue', 'brown', 'gold', 'purple', 'yellow', 'pink', 'green', 'orange']) : all effective colors
['blue', 'yellow', 'brown'] : all potential colors of bananas
['blue', 'yellow', 'brown'] : all effective colors of bananas

set(['strawberry', 'chesnut', 'pear', 'banana', 'apple']) : all potential fruits
set(['strawberry', 'pear', 'banana', 'apple']) : all effective fruits
['banana', 'pear', 'strawberry', 'apple', 'chesnut'] : all potential fruits being yellow
['banana', 'pear', 'strawberry', 'apple'] : all effective fruits being yellow

9 : number of all potential colors
8 : number of all effective colors
6 : number of potential colors of strawberry
5 : number of effective colors of strawberry

[('apple', 'blue', 21), ('apple', 'gold', 3), ('apple', 'green', 12), ('apple', 'pink', 9), ('apple', 'purple', 7), ('apple', 'silver', 0), ('apple', 'yellow', 9), ('banana', 'blue', 24), ('banana', 'brown', 14), ('banana', 'yellow', 13), ('chesnut', 'yellow', 0), ('pear', 'blue', 51), ('pear', 'brown', 5), ('pear', 'gold', 66), ('pear', 'yellow', 10), ('strawberry', 'blue', 16), ('strawberry', 'gold', 0), ('strawberry', 'green', 4), ('strawberry', 'orange', 27), ('strawberry', 'pink', 8), ('strawberry', 'yellow', 31)]   sorted li by name of fruit

[('apple', 'silver', 0), ('strawberry', 'gold', 0), ('chesnut', 'yellow', 0), ('apple', 'gold', 3), ('strawberry', 'green', 4), ('pear', 'brown', 5), ('apple', 'purple', 7), ('strawberry', 'pink', 8), ('apple', 'pink', 9), ('apple', 'yellow', 9), ('pear', 'yellow', 10), ('apple', 'green', 12), ('banana', 'yellow', 13), ('banana', 'brown', 14), ('strawberry', 'blue', 16), ('apple', 'blue', 21), ('banana', 'blue', 24), ('strawberry', 'orange', 27), ('strawberry', 'yellow', 31), ('pear', 'blue', 51), ('pear', 'gold', 66)]   sorted li by number

[('apple', 'blue', 21), ('banana', 'blue', 24), ('pear', 'blue', 51), ('strawberry', 'blue', 16), ('banana', 'brown', 14), ('pear', 'brown', 5), ('apple', 'gold', 3), ('pear', 'gold', 66), ('strawberry', 'gold', 0), ('apple', 'green', 12), ('strawberry', 'green', 4), ('strawberry', 'orange', 27), ('apple', 'pink', 9), ('strawberry', 'pink', 8), ('apple', 'purple', 7), ('apple', 'silver', 0), ('apple', 'yellow', 9), ('banana', 'yellow', 13), ('chesnut', 'yellow', 0), ('pear', 'yellow', 10), ('strawberry', 'yellow', 31)]   sorted li first by name of color and secondly by name of fruit

13voto

chmullig Points 6181

Un dictionnaire n'est probablement pas ce que vous devriez être en utilisant dans ce cas. Une plus complète de toutes les fonctionnalités de la bibliothèque serait une meilleure alternative. Probablement une vraie base de données. Le plus simple serait de sqlite. Vous pouvez garder toute chose dans la mémoire en passant par la chaîne de caractères": mémoire: "au lieu d'un nom de fichier.

Si vous ne voulez continuer dans cette voie, vous pouvez le faire avec des attributs supplémentaires à la clé ou la valeur. Toutefois, un dictionnaire ne peut pas être la clé d'un autre dictionnaire, mais un n-uplet peut. Les docs expliquer ce qui est admissible. Il doit être un objet immuable, qui comprend les chaînes de caractères, nombres et les tuples qui ne contiennent que des chaînes et des nombres (et plus de tuples contenant uniquement ces types de façon récursive...).

Vous pourriez faire votre premier exemple avec d = {('apple', 'red') : 4}, mais ça va être très dur à la requête pour ce que vous voulez. Vous auriez besoin de faire quelque chose comme ceci:

#find all apples
apples = [d[key] for key in d.keys() if key[0] == 'apple']

#find all red items
red = [d[key] for key in d.keys() if key[1] == 'red']

#the red apple
redapples = d[('apple', 'red')]

3voto

GreenMatt Points 6301

Vous pourriez avoir un dictionnaire dont les entrées sont une liste d'autres dictionnaires:

 fruit_dict = dict()
fruit_dict['banana'] = [{'yellow': 24}]
fruit_dict['apple'] = [{'red': 12}, {'green': 14}]
print fruit_dict
 

Sortie:

{'banane': [{'jaune': 24}], 'pomme': [{'rouge': 12}, {'verte': 14}]}

Edit: Comme le faisait remarquer eumiro, vous pourriez utiliser un dictionnaire de dictionnaires:

 fruit_dict = dict()
fruit_dict['banana'] = {'yellow': 24}
fruit_dict['apple'] = {'red': 12, 'green': 14}
print fruit_dict
 

Sortie:

{'banane': {'jaune': 24}, 'pomme': {'vert': 14, 'rouge': 12}}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X