0

我正在尝试比较从文件中读取的禁止文件夹列表。但是我们必须检查任务是否具有文件夹的父 ID,然后检查该文件夹是否与禁止文件夹匹配。我正在循环的列表可以包含许多项目。

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循环,这可能会很慢。我可以提高效率吗?

4

4 回答 4

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" )
于 2012-06-15T23:00:37.990 回答
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(...)操作中的每一个都可能比运行上述其中一个 for 循环花费更长的时间,但它们是未来更快查找的投资。)

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 yand..._dict[x]操作非常有效。

于 2012-06-15T23:11:17.040 回答
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

这利用了生成器,它们非常节省内存,因此可以保持速度,以及形式的条件 for 循环x for x in range(y) if condition。我建议看一下两者。

于 2012-06-15T23:55:03.973 回答
0

从原始查询中的复杂细节退后一步,一般只关注一些“​​嵌套 for 循环的替代方案”,以下内容如何:

tasks = {
    'design': 'later',
    'testing': 'desired',
    'vacation': 'fall'
}

folders = {
    'summer': 'red',
    'fall': 'gold',
    'winter': 'white',
    'spring': 'green'
}

def apply_some_logic(a, b, c, d):
    return '_'.join([a, b, c, d]) if b == c else (a, b, c, d)


if __name__ == '__main__':
    results = (apply_some_logic(a, b, c, d) for a, b in tasks.items() for c, d in folders.items())
    for result in results:
        print(result)


$ python3.6 --version
Python 3.6.4

output:
('design', 'later', 'Summer', 'Red')
('design', 'later', 'Fall', 'Gold')
('design', 'later', 'Winter', 'White')
('design', 'later', 'Spring', 'Green')
('implementation', 'urgent', 'Summer', 'Red')
('implementation', 'urgent', 'Fall', 'Gold')
('implementation', 'urgent', 'Winter', 'White')
('implementation', 'urgent', 'Spring', 'Green')
('testing', 'desired', 'Summer', 'Red')
('testing', 'desired', 'Fall', 'Gold')
('testing', 'desired', 'Winter', 'White')
('testing', 'desired', 'Spring', 'Green')
('vacation', 'Fall', 'Summer', 'Red')
vacation_Fall_Fall_Gold
('vacation', 'Fall', 'Winter', 'White')
('vacation', 'Fall', 'Spring', 'Green')
于 2018-06-14T20:16:53.580 回答