2017-05-05 1 views
1

, wie ich den Code ändern kann nur eine Schleife zu verwenden. Ich versuche .iteritems() zu verwenden, iterkeys() etc ...Python - Besserer Weg zum Einschleifen mehrdimensionale Wörterbuch

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 
) 

Es schafft Struktur wie folgt aus: data = { '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

tun Warum wollen Sie nur eine Schleife haben. Soweit ich das beurteilen kann, greifen Sie nur einmal auf jedes Element zu. Daher ist es wenig oder kein Vorteil, wenn nur eine Schleife verwendet wird, solange Sie nicht planen, die Arbeit in parallelen Threads/Prozessen auszuführen. – JohanL

+1

Der Fragesteller könnte durch die Tatsache motiviert werden, dass "flach besser ist als verschachtelt". (Zen of Python) –

Antwort

2

Als erstes müssen wir annehmen, dass jeder Benutzer nur einmal in data erscheint, weil es ein Wörterbuch ist.

Lösung 1

nun diese 2 Funktionen vorstellen:

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

Jetzt dieses Wörterbuch Verständnis tun:

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} 

Sie haben sich die Sortierung zu tun.

Lösung 2

Wir haben unsere erste Lösung modifizieren.

Einführung Funktionen

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 

Dann dieses tun

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

Mit der funktionalen Programmierung Sie würden nicht total_overtime und overtime 2X berechnen müssen.

Nach all dieser war ein klassischer Fall von diesem Muster

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

Lösung 3

Zur Überwindung CPU-Zeit Taillierung wir unsere Lösung ein wenig ändern und mit Generatoren arbeiten. Einführung Funktionen

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_} 

Jetzt

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

Ich habe deine Lösung benutzt und es funktioniert. Vielen Dank! –

+1

@DamianWysocki Ich habe vergessen, für Benutzer zu filtern, die keine Überstunden haben, habe ich es aber behoben. Sie möchten ein anderes Aussehen haben. – Elmex80s

+1

vielen Dank für Ihre Lösung ist es sehr hilfreich für mich;) –