2017-04-06 63 views
1

我有類Person像下面的對象的陣列,與thisRate第一組到None比循環查找數據更快或更好?

class Person(object): 
    def __init__(self, id, name): 
     self.id = id 
     self.name = name 
     self.thisRate= None 

予加載周圍21K Person對象到一個數組,name沒有排序。

然後我加載從數據的另一陣列,其中具有數據thisRate,其中約13K的文件時,name未排序,以及:與這些2臺陣列,

person_data = [] 

# read from file 
row['name'] = 'Peter' 
row['thisRate'] = '0.12334' 

person_data.append(row) 

現在,當name在它們之間匹配,我將從person_data分配thisRatePerson.thisRate

什麼我做的是一個循環是這樣的:

for person in persons: 
    data = None 
    try: 
     data = next(personData for personData in person_data 
         if personData['name'] == person.name) 
    except StopIteration: 
     print("No rate for this person: {}".format(person.name)) 

    if data: 
     person.thisRate = float(data['thisRate']) 

這個循環

data = next(personData for personData in person_data 
       if personData['name'] == person.name) 

運行良好,我的機器上使用21秒與Python 2.7.13。

我的問題是,有沒有更快或更好的方法來實現與我有2陣列相同的事情?

+0

當你說數組,你的意思名單? –

+0

肯定列表,在後編輯。 –

回答

4

是的。做一個字典從namethisRate

nd = {} 

with open(<whatever>) as f: 
    reader = csv.DictReader(<whatever>): 
    for row in reader: 
     nd[row['name']] = row['thisRate'] 

現在,使用這本字典在你的Person列表做單通:

for person in persons: 
    thisRate = nd.get(person.name, None) 
    person.thisRate = thisRate 
    if thisRate is None: 
     print("No rate for this person: {}".format(person.name)) 

字典有.get方法,它允許您提供一個默認值以防鑰匙不在dict中。我使用了None(實際上它是默認的默認值),但你可以使用任何你想要的。

這是一個線性時間解決方案。您的解決方案是二次的時間,因爲你基本上是這樣做的:

for person in persons: 
    for data in person_data: 
     if data['name'] == person.name: 
      person.thisRate = data['thisRate'] 
      break 
    else: 
     print("No rate for this person: {}".format(person.name)) 

只是在掩蓋這一根本嵌套的for循環發電機表達式(不是一個真正的好的用例內的發電機表達一種時尚,你應該只用一個for循環開始用,那麼你不必應付try-catch一個StopIteration

+0

的試戴捕捉是這樣的,沒有數據的人會在稍後報告進一步的行動,比如提供這個人的遺漏率 –

+1

@StevenYong可以被替換b y an [else-clause in for循環](https://docs.python.org/3.5/tutorial/controlflow.html#break-and-continue-statements-and-else-clauses-on-loops) 。 –

+2

對於這個問題,'next' + genexpr不需要提高'StopIteration'。如果沒有找到命中,'next'可以通過genexpr和默認參數:'next((personData for personData in person_data if personData ['name'] == person.name),None)'這是一個完全有效的用法案件。 – ShadowRanger