2012-06-15 91 views
0

我想比較從文件中讀取的禁止文件夾列表。但是,我們必須檢查任務是否具有文件夾的父ID,然後檢查該文件夾是否與禁止的文件夾匹配。我正在循環的列表可以包含許多項目。Python中嵌套`for`循環的替代方法

for task in tasks: 
    #Check the task is on their timesheet 
    if task["id"] == entry["item_id"]: 
     for folder in folders: 
      #See if the task is inside the folder 
      if task["parent_id"] == folder["id"]: 
       for forbiddenFolder in forbiddenFolders: 
        #If the folder is on the list 
        if forbiddenFolder == folder["name"]: 
         body_of_email +=("Using a task within a folder that is not permiited " + forbiddenFolder + "\r\n") 
         folder["name"] 
         break 

此代碼使用三個嵌套for循環,這可能會很慢。我可以提高效率嗎?

+1

當你迭代大量東西時,嵌套循環通常只是一個問題 - 在這種情況下,你基本上是在尋找一條路徑,所以它不是非常低效,因爲在大多數情況下,你會提前失敗。 –

+0

歡迎來到SO!我把你的問題稍微修改了一下 - 在每個問題結束時,沒有必要說「提前致謝」。 –

回答

2

什麼你想在這裏做的是查找一個項目(任務,文件夾) ID。 Python的字典提供了一個簡單的方法來做到這一點。如果您多次執行搜索(例如,如果有多個具有相同ID的任務,或者您將多次運行該功能),則只會保存。

另外,對於forbiddenFolders,你只需要列出一個名稱(你不查找一個項目,你只是檢查它是否存在),而Python的設置是合適的。

無論如何,這裏是你如何建立字典和集:

tasks_dict = dict((task['id'], task) for task in tasks) 
folders_dict = dict((folder['id'], folder) for folder in folders) 
forbidden_folders_set = set(forbiddenFolders) 

現在,task = tasks_dict[id]是這樣的:task['id'] == id任務,同樣的文件夾,這樣你就可以代替上面這些表達式的循環。該套件不允許這樣做,但它允許您檢查是否存在與folder in forbidden_folders_set

(記住,每個那些dict(...)操作可能比通過對以上循環一個運行更長的時間,但他們在未來更快速查找的投資。)

if entry['item_id'] in tasks_dict: 
    task = tasks_dict[entry['item_id']] 
    if task['parent_id'] in folders_dict: 
     folder = folders_dict[task['parent_id']] 
     if folder in forbidden_folders_set: 
      body_of_email += ... 

x in y..._dict[x]上述操作非常有效。

3

可以減少代碼的行數,並使其更易於理解是這樣的:基礎上,

tasks_id = [task in tasks if task["id"] == entry["item_id"]] 
folders_dict = dict() 
for folder in folders: 
    folders_dict[folder["id"]] = folder 

for task in tasks_id: 
    if task["parent_id"] in folders_dict.keys() and folder_dict[task["parent_id"]] in forbiddenFolders: 
     body_of_email +=("Using a task within a folder that is not permiited " + forbiddenFolder + "\r\n") 
+1

另外,如果forbiddenFolders的順序不相關,請爲它使用一個set:'forbiddenFolders = set('folder1','folder2 ')',然後在運行 –

1

它可以讓你保持原有的數據結構的方法如下:

for task in (t for t in tasks if entry["item_id"]==t["id"]): 
    for folder in (f for f in folders if task["parent_id"]==f["id"]): 
     for forbiddenFolder in (ff for ff in forbiddenFolders if ff==folder["name"]): 
      body_of_email += "Using a task within a folder that is not permitted %s \r\n"% forbiddenFolder 
      break 

這使得利用generators,這是非常內存效率,從而維護速度,以及有條件的for循環形式x for x in range(y) if condition的。我建議看看兩者。