Python:元组/字典作为键,select,sorting

假设我有很多不同颜色的水果,例如24个蓝色香蕉,12个青苹果,0个蓝色草莓等等。 我想用Python中的数据结构来组织它们,以便于select和sorting。 我的想法是把它们放入一个以元组为键的字典中,例如,

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

甚至字典,例如,

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

例如,我想检索所有蓝色水果或所有颜色的香蕉的清单,或者按照水果的名称对这本词典进行分类。 有没有办法以一个干净的方式做到这一点?

用元组作为关键字的字典可能不是处理这种情况的正确方法。

所有的build议欢迎!

就个人而言,我喜欢python的一个东西是tuple-dict组合。 你在这里有一个有效的二维数组(其中x =水果名和y =颜色),而且我通常是用于实现二维数组的元组字典的支持者,至less当像numpy或数据库这样的东西不是更多适当。 总而言之,我认为你有一个好方法。

请注意,不能使用字典作为字典中的键而不做一些额外的工作,所以这不是一个很好的解决scheme。

这就是说,你也应该考虑命名为() 。 这样你可以做到这一点:

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

现在你可以使用你的fruitcount字典:

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

其他技巧:

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

回应chmullig,得到一个水果的所有颜色的列表,你将不得不过滤的关键,即

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

你最好的select是创build一个简单的数据结构来build模你的模型。 然后,您可以将这些对象存储在一个简单的列表中,并按您希望的方式进行sorting/检索。

对于这种情况,我会使用下面的类:

 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) 

然后,您可以简单地构build“Fruit”实例并将其添加到列表中,如下所示:

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

简单的清单fruits将会更容易,更容易混淆,维护更好。

一些使用的例子:

下面的所有输出结果是运行给定的代码片段之后的结果:

 for fruit in fruits: print fruit 

未分类列表:

显示:

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

按名称按字母顺序sorting:

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

显示:

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

按数量sorting:

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

显示:

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

哪里颜色==红色:

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

显示:

 Name: apple, Color: red, Quantity: 12 

数据库,词典字典,词典列表字典,名为元组(它是一个子类),sqlite的,冗余…我不相信我的眼睛。 还有什么 ?

“这可能是以元组作为关键字的字典不是处理这种情况的正确方法。”

“我的直觉是,对于OP的需求来说,数据库是过分的”;

是啊! 我想

所以,在我看来,元组列表已经足够了:

 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 

结果

 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 

字典可能不是你应该在这种情况下使用。 一个更全面的function库将是一个更好的select。 可能是一个真正的数据库。 最简单的就是sqlite 。 你可以通过传递string':memory:'而不是文件名来保存整个内存。

如果你确实想继续这个path,你可以用键或值中的额外属性来完成。 然而,字典不能成为另一个字典的关键,但是一个元组可以。 文档解释了什么是可以允许的。 它必须是一个不可变的对象,它包含string,数字和元组,它们只包含string和数字(​​还有更多元组只包含那些recursion的types)。

你可以用d = {('apple', 'red') : 4}来做你的第一个例子,但是很难查询你想要的结果。 你需要做这样的事情:

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

你可以有一个字典,其中的条目是其他字典的列表:

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

输出:

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

编辑:正如eumiro指出,你可以使用字典的词典:

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

输出:

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

把键作为元组,你只需要对给定的第二个元素进行过滤和sorting:

 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工作,因为元组具有自然顺序,如果他们的组件具有自然顺序。

使用键作为相当完整的对象,只需按k.color == 'blue'过滤。

你不能真正使用字典作为键,但你可以创build一个最简单的类,如class Foo(object): pass并添加任何属性:

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

这些实例可以作为字典键,但要小心它们的可变性!

这种types的数据有效地从类似Trie的数据结构中提取。 它也允许快速分类。 记忆效率可能不是那么好。

传统的树结构将单词的每个字母存储为树中的一个节点。 但在你的情况下,你的“字母”是不同的。 您正在存储string而不是字符。

它可能看起来像这样:

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

看到这个链接: 在python中的trie

你想独立使用两个键,所以你有两个select:

  1. 将数据冗余存储为{'banana' : {'blue' : 4, ...}, .... }{'blue': {'banana':4, ...} ...} 。 然后,search和sorting很容易,但你必须确保你一起修改字典。

  2. 存储它只是一个字典,然后编写迭代它们的函数,例如:

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