2014-11-20 60 views
2

我正在寻找高效 pythonic方式来搜索和更改对象列表。优雅和pythonic方法来更改对象列表

问题很简单:咖啡对象有三个属性:名称(“Frapublabla”),颜色(“深褐色”)和味道(“苦”)。每种咖啡都有一个独特的名字,并可能有多种颜色和口味。 Barista()提供有关新咖啡的信息。一旦Barista()完成供应n种咖啡,代码将输出所有咖啡。

显而易见的,迭代的方法是这样的:

Define <coffee> - a class with three properties: name, color, taste. 
Define coffeeList = [] , tempNameList = [] 

For n times: 
    Get coffee name, color, taste from the user. Each time: 

    Search tempNameList for the name of the coffee. 
    If the coffee name is not there, then: 
     Create a new coffee object, add to coffeeList. The object includes name, color, and taste. 
     Add coffee name to tempNameList. 

    If the coffee name is found on tempNameList: 
     Iterate through the coffeeList to find the right coffee object. Then: 
      Add to that object another name or color. 

这种方法不能很好地扩展。首先,每次添加咖啡时,我们都需要搜索整个coffeeList,获取每个对象的属性。

是否有更加pythonic和优雅的方式来解决这个问题? collections.defaultdict()是我得到的最接近的,但似乎不适用于这个问题。

+3

'咖啡= {名称:{颜色:[] ,口味:[]}嵌套的词典像这样的想法 – CoryKramer 2014-11-20 20:56:40

+0

如上所述,嵌套的字典将很好地工作,如defaultdicts。 Python字典支持持续的平均时间查询,所以没有太多需要担心可伸缩性。 – jme 2014-11-20 21:08:26

回答

0

Defaultdicts绝对是继续这个的一种方式,但是,如果您正在尝试采用面向对象的方法来解决问题,那么我的个人偏好是避免嵌套字典。这是一个潜在的pythonic解决方案。

import collections 

class Coffee(): 
    def __init__(self, name='', color='', taste=''): 
     self.name = name 
     self.color = color 
     self.taste = taste 

    def __repr__(self): 
     return '{0} {1} {2}'.format(self.name, self.color, self.taste) 

prompt = "Enter name,color,taste or ctrl-d when done: " 
coffees = collections.defaultdict(Coffee) 

while True: 
    try: 
     name, color, taste = input(prompt).split(',') 
     coffees[name].name = name 
     coffees[name].color = color 
     coffees[name].taste = taste 
    except ValueError: 
     print("Try again!") 
    except EOFError: 
     print() 
     break 


print(coffees) 

+0

我会尝试这一个,并与其他方法做一些时间比较。我个人也更喜欢面向对象方法。我明天早上会在这里发布我的结果。 – 2014-11-21 03:06:43

+0

@mdadm:这个解决方案会覆盖颜色和味道,每次输入同名的咖啡。 OP指出,应该将这些属性添加到具有相同名称的咖啡对象中。 – Daniel 2014-11-23 17:28:32

0

我尝试了三种不同的方法于此,如由@Cyber​​,@jme和@mdadm以下建议:(1)面向对象的使用collections.defaultdict和(2 )正规字典,(3)嵌套字典。计时结果几乎相同。我无法回答内存使用情况和其他CPU测量结果。由于可读性和面向对象的特性,我将与#1一起进行。

以下是结果,以秒为单位。每个“尝试”迭代该代码1M次。有20个随机生成的咖啡名称,每个咖啡得到10个口味和10种颜色:

Try| Approach 1 | App 2 | App 3 | 
+--+------------+-------|-------| 
| 1| 41.1 | 42.1 | 42.1 | 
| 2| 39.1 | 41.2 | 41.6 | 
| 3| 38.6 | 41.1 | 40.1 | 
| 4| 40.9 | 42.5 | 41.3 | 
| 5| 39.5 | 40.1 | 39.7 | 

代码如下。

方法1:

import collections, random, time 

class Coffee(): 
    def __init__(self): 
     self.name = name 
     self.color = set([]) 
     self.taste = set([]) 

    def __repr__(self): 
     return '{0} {1} {2}'.format(self.name, self.color, self.taste) 

startTime = time.clock() 

coffees = collections.defaultdict(Coffee) 

for counter in range(1000000): 

    name = "Name_" + str(random.randint(1, 20)) 
    taste = "taste_" + str(random.randint(1, 10)) 
    color = "color_" + str(random.randint(1, 10)) 

    coffees[name].name = name 
    coffees[name].taste.add(taste) 
    coffees[name].color.add(color) 

print (time.clock() - startTime) 

方法2:

import random, time 

class Coffee(): 
    def __init__(self, name, color, taste): 
     self.name = name 
     self.color = set([]) 
     self.taste = set([]) 

    def __repr__(self): 
     return '{0} {1} {2}'.format(self.name, self.color, self.taste) 

startTime = time.clock() 

coffeeList = {} 

for counter in range(1000000): 

    name = "Name_" + str(random.randint(1, 20)) 
    color = "color_" + str(random.randint(1, 10)) 
    taste = "taste_" + str(random.randint(1, 10)) 

    if name not in coffeeList: 
     coffeeObj = Coffee(name, color, taste) 
     coffeeList[name] = coffeeObj 
    else: 
     coffeeList[name].color.add(color) 
     coffeeList[name].taste.add(taste) 

print (time.clock() - startTime) 

方法3:

import random, time 

coffeeNestedDict = {} 

startTime = time.clock() 

for counter in range(1000000): 

    name = "Name_" + str(random.randint(1, 20)) 
    color = "color_" + str(random.randint(1, 10)) 
    taste = "taste_" + str(random.randint(1, 10)) 

    if name not in coffeeNestedDict: 
     coffeeNestedDict[name] = {"Color" : set([color]), "Taste" : set([taste])} 

    else: 
     coffeeNestedDict[name]["Color"].add(color) 
     coffeeNestedDict[name]["Taste"].add(taste) 

print (time.clock() - startTime) 
相关问题