Python: Tuples/dictionary as key,select,sort

假设我有大量不同颜色的水果,例如,24个蓝色的香蕉,12个绿色的苹果,0个蓝色的草莓等等。 我想用 Python 中的数据结构来组织它们,以便于选择和排序。我的想法是把它们放到一个字典中,元组作为键,例如,

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

甚至字典,例如:

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

将元组作为键的字典很可能不是处理这种情况的 适当的方法。

欢迎大家提出建议!

177054 次浏览

您希望独立使用两个键,因此有两个选择:

  1. 将数据冗余地存储为 {'banana' : {'blue' : 4, ...}, .... }{'blue': {'banana':4, ...} ...}两个字母。然后,搜索和排序是很容易的,但是你必须确保你一起修改字典。

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

就个人而言,我喜欢 python 的原因之一就是它的元组-字典组合。这里实际上是一个2d 数组(其中 x = level name 和 y = color) ,我通常支持用元组的 dict 来实现2d 数组,至少在像 numpy或数据库这样的东西不太合适的时候。简而言之,我认为你有一个很好的方法。

请注意,如果不做一些额外的工作,就不能将 dicts 用作 dict 中的键,所以这不是一个很好的解决方案。

也就是说,你也应该考虑 Namedtuple ()。这样你就可以这样做:

>>> 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 = {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']

你可以拥有一本词典,其中的词条是其他词典的列表:

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

Output:

{‘香蕉’: [{‘黄色’: 24}] ,‘苹果’: [{‘红色’: 12} ,{‘绿色’: 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}}

在这种情况下,您可能不应该使用字典。一个功能更全面的库将是一个更好的选择。可能是个真正的数据库。最简单的是 斯克莱特。您可以通过传入字符串“ : memory:”而不是文件名来保存整个内存。

如果您确实希望沿着这条路径继续下去,可以使用键或值中的额外属性来完成。然而,字典不能成为另一个字典的关键,但元组可以。医生解释什么是允许的。它必须是一个不可变物件,包括只包含字符串和数字的字符串、数字和元组(以及更多只包含这些类型的递归元组... ...)。

您可以使用 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')]

使用键作为元组,您只需用给定的第二个组件筛选键并对它进行排序:

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

排序之所以有效,是因为如果元组的组件具有自然顺序,那么它们就具有自然顺序。

使用键作为相当成熟的对象,您只需通过 k.color == 'blue'进行过滤。

您不能真正使用 dicts 作为键,但是您可以创建一个最简单的类,比如 class Foo(object): pass,并在运行时向其添加任何属性:

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

这些实例可以作为 dictkey,但是要注意它们的可变性!

您的最佳选择将是创建一个简单的数据结构来对您所拥有的进行建模。然后您可以将这些对象存储在一个简单的列表中,并按照您希望的方式对它们进行排序/检索。

对于这种情况,我将使用以下类:

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)

然后您可以简单地构造“水果”实例并将它们添加到列表中,如下所示:

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.

一些使用的例子:

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

for fruit in fruits:
print fruit

未分类列表:

Displays:

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

按名字的字母顺序排列:

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

按数量分类:

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

Where color = = red:

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

这种类型的数据可以有效地从类似 Trie 的数据结构中提取。它还允许快速排序。不过,内存效率可能没有那么高。

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

it might look something like this:

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

看看这个链接: 试试蟒蛇