Python: tuples / dictionaries as keys, select, sort

Suppose I have a number of fruits of different colors, for example, 24 blue bananas, 12 green apples, 0 blue strawberries and so on. I would like to organize them in a data structure in Python, which makes it easy to select and sort. My idea was to put them in a dictionary with tuples as keys, e.g.

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

or even dictionaries, for example,

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

I would like to get a list of all blue fruits or bananas of all colors, for example, or sort this dictionary by the name of the fruit. Are there any ways to do this in a clean way?

It is possible that dictionaries with tuples as keys are not the proper way to handle this situation.

All suggestions are welcome!

+72
python dictionary select tuples key
Feb 02 '11 at 19:24
source share
8 answers

Personally, one of the things I like about python is the combination of dictators tuples. What you have here is a 2d array (where x = fruit name and y = color), and I tend to be a supporter of dict tuples to implement 2d arrays, at least when something like numpy or a database isnโ€™t more appropriate. In short, I think you have a good approach.

Note that you cannot use dicts as keys in a dict without additional work, so this is not a good solution.

However, you should also consider namedtuple () . So you can 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 file:

 >>> 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')] 

Repeating chmullig to get a list of all the colors of one fruit, you have to filter the keys, i.e.

 bananas = [fruit for fruit in fruits if fruit.name=='banana'] 
+111
Feb 02 2018-11-11T00:
source share

Your best bet is 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 in any way.

In this case, I would 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 create instances of "Fruit" and add them to the list, as shown below:

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

A simple list of fruits will be much simpler, less confusing, and better maintained.

Some examples of use:

All the outputs below are the result after the execution of the given code fragment, and then:

 for fruit in fruits: print fruit 

Unsorted list:

Output:

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

Output:

 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) 

Output:

 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) 

Output:

 Name: apple, Color: red, Quantity: 12 
+17
02 Feb '11 at 20:13
source share

Database, dict of dicts, dictionary list dictionary, named tuple (this is a subclass), sqlite, redundancy ... I could not believe my eyes. What else?

"It is entirely possible that dictionaries with tuples as keys are not the right way to handle this situation."

"my gut feeling is that the database is too much for OP needs";

Yes! I thought that

So, in my opinion, the list of tuples is quite a lot:

 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 

result

 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 
+17
Feb 02 2018-11-11T00:
source share

The dictionary is probably not the one you should use in this case. A better alternative would be a more fully functional library. Probably a real database. The easiest way is sqlite . You can save all this in memory by passing in the line ': memory:' instead of the file name.

If you want to continue this path, you can do this with additional attributes in the key or value. However, a dictionary cannot be the key to another dictionary, but a tuple can. Documents explain what is permissible. It should be an immutable object, which includes strings, numbers, and tuples that contain only strings and numbers (and more tuples containing only these types, recursively ...).

You can do your first example with d = {('apple', 'red') : 4} , but it will be very difficult to request what you want. You will need to do something like this:

 #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')] 
+11
Feb 02 '11 at 19:37
source share

You may have a dictionary in which entries are a list of other dictionaries:

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

Output:

{'banana': [{'yellow': 24}], 'apple': [{'red': 12}, {'green': 14}]}

Edit: As eumiro pointed out, you can use a dictionary of dictionaries:

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

Output:

{'banana': {'yellow': 24}, 'apple': {'green': 14, 'red': 12}}

+3
Feb 02 2018-11-11T00:
source share

Using keys as tuples, you simply filter out the keys with the specified second component and sort it:

 blue_fruit = sorted([k for k in data.keys() if k[1] == 'blue']) for k in blue_fruit: print k[0], data[k] # prints 'banana 24', etc 

Sorting works because tuples are in natural order if their components are in natural order.

Using keys as full-featured objects, you simply filter k.color == 'blue' .

You cannot use dicts as keys, but you can create a simple class, for example class Foo(object): pass , and add any attributes on the fly to it:

 k = Foo() k.color = 'blue' 

These instances can serve as dict keys, but beware of their variability!

+3
02 Feb '11 at 19:52
source share

You want to use two keys yourself, so you have two options:

  • Save data redundantly with two dicts as {'banana' : {'blue' : 4, ...}, .... } and {'blue': {'banana':4, ...} ...} . Finding and sorting is then simple, but you have to make sure that you modify the dicts together.

  • Save it with only one dict, and then write functions that iterate over them, for example:

     d = {'banana' : {'blue' : 4, 'yellow':6}, 'apple':{'red':1} } blueFruit = [(fruit,d[fruit]['blue']) if d[fruit].has_key('blue') for fruit in d.keys()] 
+2
Feb 02 2018-11-11T00:
source share

This data type is effectively extracted from a data structure similar to Trie. It also allows quick sorting. Memory efficiency may not be that big.

A traditional trie stores each letter of a word as a node in a tree. But in your case, your "alphabet" is different. You save strings instead of characters.

it might look something like this:

 root: Root /|\ / | \ / | \ fruit: Banana Apple Strawberry / | | \ / | | \ color: Blue Yellow Green Blue / | | \ / | | \ end: 24 100 12 0 

see this link: trie in python

+2
Apr 18 '13 at 21:04 on
source share



All Articles