2017-05-05 68 views
1

如何將我的代碼更改爲僅使用一個循環。我嘗試使用.iteritems(),出iterkeys()等等......Python - 循環多維詞典的更好方法

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 
) 

它創建結構是這樣的: 數據= { 'USER_ID':{ 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

爲什麼你要只有一個循環。據我所知,你只能訪問每個元素一次。因此,只要你不打算在並行線程/進程中執行工作,僅使用一個循環幾乎沒有收益。 – JohanL

+1

提問者可能會被「平坦比嵌套更好」的事實所激發。 (Python的禪) –

回答

2

首先要說的是,我們可以假設每個用戶在data中只出現一次,因爲它是一本字典。

解決方案1 ​​

下面介紹這2個功能:

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)} 
+0

我用你的解決方案,它的工作。謝謝! –

+1

@DamianWysocki我忘記過濾沒有超時的用戶,但是我修復了它。你想再看一次。 – Elmex80s

+1

非常感謝您的解決方案,它對我非常有幫助;) –