Zeitstempel Gruppieren und Addieren nach Jobs

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Omm
User
Beiträge: 90
Registriert: Samstag 7. April 2018, 14:05

Hallo zusammen
ich hab folgendes was ich machen möchte:

logdatei(log.txt) sieht als Beispiel so aus:
Do, 12.04.2018, 08:00:00; xxx
Do, 12.04.2018, 09:00:00; ccc
Do, 12.04.2018, 10:00:00; FEIERABEND
Fr, 13.04.2018, 08:00:00; bbb
Fr, 13.04.2018, 09:00:00; rrr
Fr, 13.04.2018, 10:00:00; ccc
Fr, 20.04.2018, 11:00:00; xxx
Fr, 20.04.2018, 12:00:00; MITTAG
Fr, 20.04.2018, 13:00:00; xxx
Fr, 20.04.2018, 14:00:00; FEIERABEND

Code: Alles auswählen

    def auswertung(self, event, name_fix=None):
        logdatei = self.read_log_file()
        status = self.compare_timestamps(logdatei)
        if status:
            LAufgaben = list(logdatei)
            jobs = [(z.split('; ', 1)[-1]).strip() for z in LAufgaben]
            jobs = list(OrderedDict.fromkeys(jobs).keys())
            if 'FEIERABEND' in jobs: jobs.remove('FEIERABEND')
            if 'MITTAG' in jobs: jobs.remove('MITTAG')
            print(jobs))
Am Ende müsste das so aussehen:
xxx 3h
ccc 2h
bbb 1h
rrr 1h

Das ganze je nach gewünschtem Zeitfenster auf Woche Monat oder den Tag zusammengestellt. Momentan geht es mir aber nur um das Ziel oben.

Python ist für mich neu.. :oops:
Kann mir da jemand bitte ansatzweise helfen, wie ich das am besten machen kann. Array, Matrix oder ?? Weiter als oben komme ich nicht.
Sirius3
User
Beiträge: 17745
Registriert: Sonntag 21. Oktober 2012, 17:20

Also ist Deine Funktion compare_timestamps überflüssig, bzw. das ist die Funktion, die Du erweitern müßtest. Zeitdauer ist die Differenz zwischen Zeitstempel nächster Eintrag zu Zeitstempel aktueller Eintrag. Ist diese Differenz negativ, stimmt was nicht. Gleichzeitig kannst Du die Zeiten in Deinem OrderedDict zusammenzählen.

Zu Deinem Code: LAufgabe ist das selbe wie logdatei, also überflüssig. jobs vorher herauszufinden ist überflüssig, weil die ja beim Aufbau des Wörterbuchs automatisch zusammenkommen. FEIERABEND und MITTAG sollten erst ganz zum Schluß entfernt (ignoriert) werden.
Omm
User
Beiträge: 90
Registriert: Samstag 7. April 2018, 14:05

Hallo Sirius3

der Übersichtshalber wollte ich das getrennt haben. Aber ich sehe schon, es ist nicht nötig.

Du sprichst von OrderedDict geht auch Dict, oder ist das egal? Das sind lowlevel Fragen, sorry.
Sirius3
User
Beiträge: 17745
Registriert: Sonntag 21. Oktober 2012, 17:20

Du hast ein OrderedDict benutzt, so dachte ich, die Reihenfolge wäre Dir wichtig.
Omm
User
Beiträge: 90
Registriert: Samstag 7. April 2018, 14:05

so mein Zwischenstandt.

wie kann im im Key ein Format definieren. Momentan ist das ein Int.
Damit ich deltatime + value_key nutzen kann. Oder muss ich über Int gehen?

Code: Alles auswählen


    def compare_timestamps(self,event, name_fix=None):
        logfile = self.read_log_file()
        jobs = [(z.split('; ', 1)[-1]).strip() for z in logfile]
        jobs = list(OrderedDict.fromkeys(jobs).keys())
        jobdict = OrderedDict([i,jobs.count(i)]for i in jobs)

        print(jobdict.keys())

        last_entry = None
        for date in logfile:
            timestamp = datetime.datetime.strptime(date[4:24], "%d.%m.%Y, %H:%M:%S")
            if last_entry is not None:
                if last_entry > timestamp:
                    print(date)
                    return False

            if last_entry :
                deltatime = timestamp - last_entry
                key_aus_timestamp = date[26:]
                key_aus_timestamp = key_aus_timestamp.replace("\n", "")
                value_key = jobdict.get(key_aus_timestamp)
                jobdict[key_aus_timestamp] = deltatime + value_key
                print(date, deltatime)

            last_entry = timestamp
        return True
Sirius3
User
Beiträge: 17745
Registriert: Sonntag 21. Oktober 2012, 17:20

Du gehst die Liste immer noch mehrfach durch, übersichtlicher und lesbarer ist es, einmal das log-File durchzugehen und
1) die Zeile an ';' splitten in timestamp und job
2) die Differenz zum vorherigen timestamp bilden und in einem Wörterbuch zur Zeit des vorherigen Jobs draufaddieren.

Benutze split, statt den direkten Indexzugriff. Benutze strip statt replace (aber das hast Du ja alles schon richtig in Zeile 2 deiner Funktion gemacht? Warum dann später so umständlich und Fehleranfällig?)

Die Rückgabe sollte das Wörterbuch sein und eine Exception im Fehlerfall.
Omm
User
Beiträge: 90
Registriert: Samstag 7. April 2018, 14:05

ok, jetzt habe ich es angepasst.
sieht einfacher aus. :P

Code: Alles auswählen

    def compare_timestamps(self,event, name_fix=None):
        logfile = self.read_log_file()
        last_entry = None
        for line in logfile:
            job = line[26:]
            timestamp = datetime.datetime.strptime(line[4:24], "%d.%m.%Y, %H:%M:%S")
            print(job,timestamp)

            if last_entry is not None:
                if last_entry > timestamp:
                    print(line)
            if last_entry:
                deltatime = timestamp - last_entry
                print(deltatime)
            last_entry = timestamp
Was ich nicht vertehe ist was Du mit dem Wörterbuch meinst. Googel konnte mir nicht wirklich helfen. Hast du ein Beispiel oder sowas?
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

Dictionary = Wörterbuch, vielleicht hilft Dir das weiter. Aber beschreibe doch noch einmal, was Du genau erreichen möchtest, was Deine Funktion bislang macht, warum Du das so umgesetzt hast und wie Du weiter vorgehen möchtest. Das hilft insbesondere auch Dir, die Aufgabe zu verstehen.
Omm
User
Beiträge: 90
Registriert: Samstag 7. April 2018, 14:05

kbr hat geschrieben: Mittwoch 30. Mai 2018, 18:54 Dictionary = Wörterbuch, vielleicht hilft Dir das weiter. Aber beschreibe doch noch einmal, was Du genau erreichen möchtest, was Deine Funktion bislang macht, warum Du das so umgesetzt hast und wie Du weiter vorgehen möchtest. Das hilft insbesondere auch Dir, die Aufgabe zu verstehen.
was der Code am Schluss mache soll und wohin ich damit möchte, ist im ersten Post beschrieben.
Ich denke mal, dass ich hier als newcommer in Python so wie Programmieren generell, an meine Grenze angelangt bin.
Wenn du den Verlauf des Codes siehst weisst du was ich meine. :lol:
Ich sag mal besser nicht, wie lange ich dafür gebraucht habe.
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Omm hat geschrieben: Mittwoch 30. Mai 2018, 19:35 Ich denke mal, dass ich hier als Newcomer in Python so wie Programmieren generell, an meine Grenze angelangt bin.
Wenn du den Verlauf des Codes siehst weisst du was ich meine. :lol:
Ich sag mal besser nicht, wie lange ich dafür gebraucht habe.
Es ist egal wie lange du gebraucht hast.
Wichtig ist, dass du nicht aufgibst, sondern deine Grenzen täglich erweiterst.
Learning by doing.
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Omm
User
Beiträge: 90
Registriert: Samstag 7. April 2018, 14:05

Code: Alles auswählen

    def compare_timestamps(self,event, name_fix=None):
        logfile = self.read_log_file()
        last_entry = None
        counter = 0
        last_deltatime = datetime.strptime("00:00:00", "%H:%M:%S")
        deltatime =  datetime.strptime("00:00:00", "%H:%M:%S")
        dictionary = {}
        for line in logfile:
            job = line[26:].replace("\n", "")
            timestamp = datetime.strptime(line[4:24], "%d.%m.%Y, %H:%M:%S")

            if last_entry is not None:
                if last_entry > timestamp:
                    print(line)

            if last_entry:

                deltatime = timestamp - last_entry
                print(deltatime)
                print(dictionary[prejob][1])  #!!
                dictionary[prejob] = deltatime 

            last_entry = timestamp
            last_deltatime = deltatime
            prejob = logfile[counter]
            prejob = line[26:].replace("\n", "")
            counter = counter + 1
schön ist was anderes.
Wie kann ich einen Wert aus der Werteliste auslesen. print(dictionary[prejob][1]) #!! geht nicht.
Momentan wird einfach der Wert überschrieben und nich addiert.
Omm
User
Beiträge: 90
Registriert: Samstag 7. April 2018, 14:05

Code: Alles auswählen

       def compare_timestamps(self,event, name_fix=None):
        logfile = self.read_log_file()
        last_entry = None
        counter = 0
        last_deltatime = datetime.strptime("00:00:00", "%H:%M:%S")
        deltatime = datetime.strptime("00:00:00", "%H:%M:%S")
        dictionary = {}

        for line in logfile:
            job = line[26:].replace("\n", "")
            dictionary[job] = deltatime

        for line in logfile:
            timestamp = datetime.strptime(line[4:24], "%d.%m.%Y, %H:%M:%S")
            if last_entry is not None:
                if last_entry > timestamp:
                    print("Fehler in der Zeitstempelung: ", line)
            if last_entry:
                deltatime = timestamp - last_entry
                dictionary[prejob] = deltatime + dictionary[prejob]
            last_entry = timestamp
            last_deltatime = deltatime
            prejob = logfile[counter]
            prejob = line[26:].replace("\n", "")
            counter = counter + 1

        if 'MITTAG' in dictionary: del dictionary['MITTAG']
        if 'FEIERABEND' in dictionary: del dictionary['FEIERABEND']
        print("bin durch", dictionary)
so geht es. Zuerst Werteliste vorbereiten, dann reinschreiben! Das soll mal einer verstehen.
Jedoch, sieht es fürchterlich aus. Evtl. kann mir jemand sagen, wie ich das einwenig aufräumen kann. Wäre sehr lieb. :)
Sirius3
User
Beiträge: 17745
Registriert: Sonntag 21. Oktober 2012, 17:20

Du mußt eben prüfen, ob schon ein Wert mit dem Schlüssel im Wörterbuch ist, bevor Du ihn abfrägst. Händisch:

Code: Alles auswählen

if prejob not in dictionary:
    dictionary[prejob] = deltatime
else:
    dictionary[prejob] += deltatime
oder Du benutzt ein defaultdict.

Die beiden if-Abfragen in der Schleife sind die selben und können zusammengefasst werden. last_deltatime wird nie benutzt. Die erste Zuweisung zu prejob wird sofort wieder überschrieben, kann also weg und damit auch dieser counter, den man, falls man ihn wirklich braucht, besser über enumerate macht.
Aufgeräumt, sieht das also so aus:

Code: Alles auswählen

    def compare_timestamps(self,event, name_fix=None):
        logfile = self.read_log_file()
        last_entry = None
        dictionary = {}
        for line in logfile:
            timestamp = datetime.strptime(line[4:24], "%d.%m.%Y, %H:%M:%S")
            if last_entry is not None:
                if last_entry > timestamp:
                    print("Fehler in der Zeitstempelung: ", line)
                deltatime = timestamp - last_entry
                if prejob not in dictionary:
                    dictionary[prejob] = deltatime
                else:
                    dictionary[prejob] += deltatime
    
            last_entry = timestamp
            prejob = line[26:].replace("\n", "")
        return dictionary
Jetzt sind noch die Variablennamen allesamt schlecht, weil sie nichts aussagen, für was sie stehen. `compare_timestamps` vergleicht ja (nicht nur) Zeitpunkte. `event`, `name_fix` werden nicht verwendet. Da die for-Schleife quasi immer schon die nächste, statt der aktuellen Zeile durchgeht, ist `last_entry` eigentlich `current_timestamp`, `line` dann `next_line`, `prejob` `current_job` und `timestamp` `next_timestamp`. Dass Du das Gemurkse mit Stringindizierung und replace schonmal besser gelöst hattest, habe ich Dir ja schon mehrfach geschrieben. `dictionary` ist so ein generischer Begriff, dass die Variable besser job_durations heißen sollte.

Code: Alles auswählen

    def parse_logfile(self, _event, _name_fix=None): # Parameter werden nicht verwendet
        logfile = self.read_log_file()
        job_durations = {}
        current_timestamp = None
        for line in logfile:
            next_job, next_timestamp = line.split(';', 1)
            next_timestamp = datetime.strptime(next_timestamp, "%d.%m.%Y, %H:%M:%S")
            if current_timestamp is not None:
                if current_timestamp > next_timestamp:
                    raise ValueError("Fehler in der Zeitstempelung: ", line)
                duration = next_timestamp - current_timestamp
                if current_job not in job_durations:
                    job_durations[current_job] = duration
                else:
                    job_durations[current_job] += duration
    
            current_timestamp = next_timestamp
            current_job = next_job.strip()
        return job_durations
Omm
User
Beiträge: 90
Registriert: Samstag 7. April 2018, 14:05

Du machst mir fertig. :lol:
Ich mache schon ca. 3Tag daran und Du bröselst das so hin.
Eine Zeile musste ich anpassen. Dank Deiner Umbenennung konnte ich den Fehler im Debug schnell finden.

Code: Alles auswählen

next_job, next_timestamp = line.split(';', 1)
jetzt sieht es so aus.

Code: Alles auswählen

      def parse_logfile(self, _event, _name_fix=None):  # Parameter werden nicht verwendet
        logfile = self.read_log_file()
        job_durations = {}
        current_timestamp = None
        for line in logfile:
            next_timestamp, next_job = line.split(';', 1)
            next_timestamp = next_timestamp[4:]
            next_timestamp = datetime.strptime(next_timestamp, "%d.%m.%Y, %H:%M:%S")
            if current_timestamp is not None:
                if current_timestamp > next_timestamp:
                    raise ValueError("Fehler in der Zeitstempelung: ", line)
                duration = next_timestamp - current_timestamp
                if current_job not in job_durations:
                    job_durations[current_job] = duration
                else:
                    job_durations[current_job] += duration

            current_timestamp = next_timestamp
            current_job = next_job.strip()

        if 'MITTAG' in job_durations: del job_durations['MITTAG']
        if 'FEIERABEND' in job_durations: del job_durations['FEIERABEND']    
        return job_durations
Damit ist die grösste Hürde geschafft.
Vielen Vielen Dank.

Also wenn ich nun zurück schaue, muss ich sagen Python ist cool. Das Problem ist aber, wenn man sich alles selber beibringen möchte, benötigt man unglaublich viel Zeit und Geduld. Um am Schluss zu sehen, dass mann noch nichts kann. hehe
Nochmals vielen Dank an alle. :P Ich bleibe dran.
Antworten