Python: Tuples/dictionaries as keys, select, sort
Suppose I have quantities of fruits of different colors, e.g., 24 blue bananas, 12 green apples, 0 blue strawberries and so on. I'd like to organize them in a data structure in Python that allows for easy selection and sorting. My idea was to put them into a dictionary with tuples as keys, e.g.,
{
('banana', 'blue' ): 24,
('apple', 'green'): 12,
('strawberry','blue' ): 0,
# ...
}
or even dictionaries, e.g.,
{
{'fruit': 'banana', 'color': 'blue' }: 24,
{'fruit': 'apple', 'color': 'green'}: 12,
{'fruit': 'strawberry','color': 'blue' }: 0,
# ...
}
I'd like to retrieve a list of all blue fruit, or bananas of all colors, for example, or to sort this dictionary by the name of the fruit. Are there ways to do this in a clean way?
It might well be that dictionaries with tuples as keys are not the proper way to handle this situation.
All suggestions welcome!
Personally, one of the things I love about python is the tuple-dict combination. What you have here is effectively a 2d array (where x = fruit name and y = color), and I am generally a supporter of the dict of tuples for implementing 2d arrays, at least when something like numpy
or a database isn't more appropriate. So in short, I think you've got a good approach.
Note that you can't use dicts as keys in a dict without doing some extra work, so that's not a very good solution.
That said, you should also consider namedtuple(). That way you could do this:
>>> 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'
Now you can use your fruitcount dict:
>>> fruitcount = {Fruit("banana", "red"):5}
>>> fruitcount[f]
5
Other tricks:
>>> 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')]
Echoing chmullig, to get a list of all colors of one fruit, you would have to filter the keys, i.e.
bananas = [fruit for fruit in fruits if fruit.name=='banana']
Your best option will be to create a simple data structure to model what you have. Then you can store these objects in a simple list and sort/retrieve them any way you wish.
For this case, I'd use the following class:
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)
Then you can simply construct "Fruit" instances and add them to a list, as shown in the following manner:
fruit1 = Fruit("apple", "red", 12)
fruit2 = Fruit("pear", "green", 22)
fruit3 = Fruit("banana", "yellow", 32)
fruits = [fruit3, fruit2, fruit1]
The simple list fruits
will be much easier, less confusing, and better-maintained.
Some examples of use:
All outputs below is the result after running the given code snippet followed by:
for fruit in fruits:
print fruit
Unsorted list:
Displays:
Name: banana, Color: yellow, Quantity: 32
Name: pear, Color: green, Quantity: 22
Name: apple, Color: red, Quantity: 12
Sorted alphabetically by name:
fruits.sort(key=lambda x: x.name.lower())
Displays:
Name: apple, Color: red, Quantity: 12
Name: banana, Color: yellow, Quantity: 32
Name: pear, Color: green, Quantity: 22
Sorted by quantity:
fruits.sort(key=lambda x: x.quantity)
Displays:
Name: apple, Color: red, Quantity: 12
Name: pear, Color: green, Quantity: 22
Name: banana, Color: yellow, Quantity: 32
Where color == red:
red_fruit = filter(lambda f: f.color == "red", fruits)
Displays:
Name: apple, Color: red, Quantity: 12