Python - 循环多维字典的更好方法

时间:2017-05-05 11:16:06

标签: python functional-programming

如何将代码更改为仅使用一个循环。我尝试使用.iteritems(),iterkeys()等......

for user in data:
    for item in data[user]:
        start = seconds_since_midnight(
            data[user][item]['start']
        )
        end = seconds_since_midnight(
            data[user][item]['end']
        )
        overtime = end - start

        if overtime > eight_hours:
            if user not in result:
                if str(user) not in names.keys():
                    continue
                result[user] = {
                    'name': names[str(user)]['name'],
                    'overtime': []
                }

            result[user]['overtime'].append(overtime - eight_hours)
    try:
        result[user]['overtime'] = sum(result[user]['overtime'])
    except KeyError:
        pass

return sorted(
    result.items(),
    key=lambda result: result[1]['overtime'],
    reverse=True
)
  

它创建这样的结构:       data = {      '用户身份': {      datetime.date(2013,10,1):{        'start':datetime.time(9,0,0),                   'end':datetime.time(17,30,0),               },               datetime.date(2013,10,2):{                   'start':datetime.time(8,30,0),                   'end':datetime.time(16,45,0),               },           }       }

1 个答案:

答案 0 :(得分:2)

首先要注意的是我们可以假设每个用户只在data中出现一次,因为它是一个字典。

解决方案1 ​​

现在介绍这两个功能:

def overtime(item):
    start = seconds_since_midnight(item['start'])
    end = seconds_since_midnight(item['end'])

    return end - start


def comp_hours(name, items):
    return {'name': name, 
            'overtime': sum(overtime(item) - 8 for item in items if overtime(item) > 8)}

现在做这个字典理解:

result = {u: comp_hours(names[str(u)]['name'], i) for u, i in data.items() if str(u) in names}
result_filtered = {k: v for k, v in result.items() if v > 0}

你必须自己进行排序。

解决方案2

我们修改了第一个解决方案。

介绍功能

def total_overtime(items):
    return sum(overtime(item) - 8 for item in items if overtime(item) > 8)


def comp_hours_new(user, items):
    return {'name': names[str(user)]['name'], 'overtime': total_overtime(items)}


def condition(user, items):
    return str(user) in names and total_overtime(items) > 0

然后这样做

{u: comp_hours_new(u, i) for u, i in data.items() if condition(u, i)}

使用函数式编程,您不必计算total_overtimeovertime 2X。

毕竟这个是这种模式的经典案例

{k: f(k, v) for k, v in your_dict.items() if condition(k, v)}

解决方案3

为了克服缓慢的CPU时间,我们稍微修改了我们的解决方案,并将使用生成器。 介绍功能

def condition_new(user, total_overtime_):
    return str(user) in names and total_overtime_ > 0


def comp_hours_new_new(user, total_overtime_):
    return {'name': names[str(user)]['name'], 'overtime': total_overtime_}

现在做

I = ((u, total_overtime(i)) for u, i in data.items())
{u: comp_hours_new_new(u, ttl_over) for u, ttl_over in I if condition_new(u, ttl_over)}