2014-11-20 77 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)