Join-Methode

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.
LukeNukem
User
Beiträge: 232
Registriert: Mittwoch 19. Mai 2021, 03:40

bahmady hat geschrieben: Montag 7. Juni 2021, 15:18 Was ich von deinem Code verstehe:
(...)
Hier soll eine Fehlermeldung auftauchen, falls die beiden Textdateien unterschiedlich lange Zeilen haben.
Korrekt.
bahmady hat geschrieben: Montag 7. Juni 2021, 15:18 (...)
Hier bildest du den Formatstring. Was ich an deinem Code nicht verstehe ist, wie du contents verwendest und wie du die Bezüge darstellst:
Mein Trick ist, daß ich mit der zip()-Funktion zunächst eine Liste von Tupeln baue, und jedes der Tupel-Elemente in der Liste enthält die Inhalte der korrespondierenden Zeilen. Also das Tupel mit dem Index 0 in der Liste enthält die Daten der ersten, das Tupel-Element mit dem Index 1 in der Liste die aus der zweiten Zeile, und so weiter. Dadurch kann ich ganz einfach über eine weitere List Comprehension die Längen der Strings in den Zeilen ermitteln und mit der max()-Funktion die größte Länge dort herausziehen, und mit dieser Länge baue ich dann einen Teil-Formatstring wie "{:<30s}" für einen linksbündig ausgerichteten String mit 30 Zeichen. Diese Teil-Formatstrings werden dann über die str.join()-Methode zum Gesamt-Formatstring zusammengefaßt.

Nun habe ich meine originalen Inhalte aber noch in der Variablen "content", die ebenfalls eine Liste von Listen ist und in jeder der enthaltenen Listen die eingelesenen Inhalte einer meiner Textdateien enthält -- also das, was ich bei '--serial' oder '-s' in einer Zeile ausgeben möchte. Und genau darauf wende ich dann ganz einfach meinen oben zusammengebauten Formatstring an und gebe das Resultat aus.
bahmady hat geschrieben: Montag 7. Juni 2021, 15:18 (...)
Wo ist der Bezug von filename zu meinen beiden Textdateien???
Na klar. Ich habe den ArgumentParser so konfiguriert, daß er sogenannte "positional arguments" entgegennehmen kann, sowas kennst Du vielleicht (hoffentlich) von etlichen Kommandozeilenprogrammen wie less(1), cat(1) oder grep(1). So kannt Du mein Programm im Prinzip mit so vielen Dateinamen aufrufen, wie Du möchtest, bei Dir zum Beispiel mit zwei: "./programm.py names.txt numbers.txt", aber "./programm.py names.txt numbers.txt numbers.txt names.txt" oder andere Dateien gehen natürlich auch. (Es gibt da eine Grenze, die Deine Kommandozeilenumgebung festlegt, aber die ist heutzutage recht groß und soll uns jetzt hier nicht weiter interessieren). Der Name "filenames" und der Parameter "nargs='+'" in "parser.add_argument()" sorgen dafür, daß die übergebenen Dateinamen von parser.parse_args() in einer Liste (hier: "args") abgelegt werden, die Dein Programm dann im Folgenden über das Attribut "args.filenames" lesen, und -- wie ich hier -- darüber iterieren kann. Wenn Du das Programm also mit "./programm.py names.txt numbers.txt" aufrufst, enthält args.filenames nach dem Aufruf von parse_args() die Liste "['names.txt', 'numbers.txt']" -- und wenn ich mit "for filename in args.filenames:" darüber iteriere... genau.
bahmady hat geschrieben: Montag 7. Juni 2021, 15:18 (...)
Kannst du mir den Bezug von 'filenames' zu contents erklären? Ich bin übrigens schon für Datenbanksysteme am lernen. Die nächsten Klausurtermine sind erst ab Oktober -.-. Die Klausur ist am 17.07...
Naja, die "args.filenames" sind wie gerade erklärt die übergebenen Dateinamen, und "filename" enthält dann für jeden Durchlauf der for-Schleife einen der Dateinamen. Ich öffne dann die Datei mit einem sogenannten "Context Manager" (with open()") zum Lesen, lese die Datei komplett ein, splitte den gelesenen Inhalt zeilenweise ("ifh.read().splitlines()") und hänge die so gewonnene Liste von Zeilen an meine Liste "contents" an, so daß "contents" am Ende eine Liste enthält, bei der jedes Element wiederum eine Liste der Zeilen aus der angegebenen Textdatei ist.

Tipp: füg' doch mal' nach dem "corresponding_lines" jeweils ein "print(contents)" und ein "print(corresponding_lines)" ein... viel Spaß und Erfolg! ;-)
bahmady
User
Beiträge: 12
Registriert: Sonntag 30. Mai 2021, 15:59

Nach 31 Beiträgen mehr Fragezeichen als vorher...danke Leute!
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

bahmady hat geschrieben: Freitag 11. Juni 2021, 15:49 Nach 31 Beiträgen mehr Fragezeichen als vorher...danke Leute!
Man kann dir bestimmt helfen. Viele von uns, mich inbegriffen, haben aber anscheinend immer noch nicht ganz verstanden was die genaue Anforderung ist.
Zeig doch nochmal wie die Ausgabe aussehen soll, aber mit [\code] - tags damit die Formatierung nicht verändert wird.
Bisher hattest du auch nur einen Teil der Aufgabe gepostet, daher ist es nicht ganz klar wie das mit dem Rest des Programms zusammenspielen soll.

Es ist wohl auch zielführender, wenn du uns deinen Code zeigst und wir dir Hilfestellung an deinem Code geben.
LukeNukem
User
Beiträge: 232
Registriert: Mittwoch 19. Mai 2021, 03:40

bahmady hat geschrieben: Freitag 11. Juni 2021, 15:49 Nach 31 Beiträgen mehr Fragezeichen als vorher...danke Leute!
Najaaa... Du möchtest oder mußt die Programmiersprache Python lernen. Zum Erlernen einer Programmiersprache ist es meist sehr nützlich, fremden Code zu lesen und zu verstehen -- oder sich jedenfalls ein Verständnis dafür zu erarbeiten. Und zwar, ja, auch Code von Leuten, die mehr Erfahrung haben als man selbst, dabei lernt man gemeinhin am meisten. Und wenn ich Dein Eröffnungsposting richtig verstanden habe, möchtest Du Dir das Verständnis ja auch erarbeiten und keine schlüsselfertige Lösung.

Deswegen, mach's doch einfach so: nimm meinen Code und arbeite ihn Abschnitt für Abschnitt durch. Wenn Du Dich fragst, was in "args.filenames" steht, dann füg' doch einfach mal temporär ein "print('args.filenames:', args.filenames)" oder ein "print('args:', args)" ein. "print()" ist quasi das "Debugging des kleinen Mannes", und auch die Builtin-Funktionen "dir()", "vars()", "type()" und ggf. "getattr()" können dabei sehr nützlich sein, um ein Python-Objekt zu untersuchen. Wenn Du Dein "print()"-Statement eingebaut hast, rufst Du das Programm einfach mal auf und schaust, was in Deinen Variablen steht. Dabei kann es nützlich sein, das Programm nach dem Aufruf von "print()" direkt zu beenden, das ginge mit einem "sys.exit(0)". Wenn Du das Programm einige Male mit verschiedenen Kommandozeilenargumenten aufgerufen und den Zusammenhang zwischen den Argumenten und den Inhalten von "args.filenames" bzw. "args" verstanden hast, nimmst Du das (oder die) "print()"-Aufrufe wieder heraus und wendest Dich dem nächsten Abschnitt des Code zu.

Mein Code benutzt -- bewußt -- viele Comprehensions, also im Prinzip eine Art von syntaktischem Zucker. Dabei ist die List Comprehension

Code: Alles auswählen

dingsbums = [1, 2, 3]
bumsdings = [value**value for value in dingsbums]
quasi so etwas wie eine Kurzform von

Code: Alles auswählen

dingsbums = [1, 2, 3]
bumsdings = list()
for value in dingsbums: 
    bumsdings.append(value**value)
Also probier' mal Folgendes: zieh' meine Comprehensions auseinander, also überführe sie in ihre Langform, und um zu verstehen, was passiert, fügst Du dort -- wie zuvor -- wieder "print()"-Statements ein.

Auf diese Weise arbeitest Du Dich durch den Code und verstehst Stück für Stück das Programm -- und wenn sich dabei Fragen ergeben, dann stell' sie einfach hier. Ja, ich weiß, das ist zeit- und arbeitsaufwändig, aber am Ende, wenn Du alles verstanden hast, wirst Du mit Deinen Python-Kenntnissen ein bedeutendes Stück weiter gekommen sein.

Wie gesagt, ich weiß, das ist aufwändig, aber leider ist es der einzige Weg. Wir können ja schlecht Deinen Kopf aufmachen und unser Wissen hineinkopieren, und wenn wir Dir die einfachste und Deinem aktuellen Niveau angepaßte Lösung vorkauen, hast Du auch nicht viel gelernt. Da können wir Dir helfen und ich glaube, wir haben gezeigt, daß wir das auch gerne tun, aber mehr können wir nicht tun... :-)
bahmady
User
Beiträge: 12
Registriert: Sonntag 30. Mai 2021, 15:59

Hallo zusammen!

Sorry für die späte Antwort. Ich lerne gerade für eine andere Klausur. Nach der Klausurphase mache ich einen Python-Bootcamp, um beim Programmieren besser zu werden. Dies wird jedoch leider erst im September sein -.-

@LukeNukem ich habe die Aufgabe mittlerweile gelöst. Hierzu habe ich deinen Code genommen, den Argparser entfernt und den Code entsprechend modifiziert. Hier mein Code:

Code: Alles auswählen

texteins = 'C:/Users/bah90/Desktop/names.txt'
textzwei = 'C:/Users/bah90/Desktop/numbers.txt'

def paste_s(texteins, textzwei):
    #texteins lesen und splitten
    texteins = open('C:/Users/bah90/Desktop/names.txt', encoding='utf-8') 
    namen = texteins.read()
    namen_split = namen.splitlines(False)
    texteins.close()
    #testzwei lesen und splitten
    textzwei = open('C:/Users/bah90/Desktop/numbers.txt', encoding='utf-8')
    nummern = textzwei.read()
    nummern_split = nummern.splitlines(False)
    textzwei.close()
    #Inhalt beider Dateien zu einer Gesamtliste hinzufügen
    listen = list()
    listen.append(namen_split)
    listen.append(nummern_split)
    #Gesamtliste in zusammengehörige Elemente aufteilen
    zusammengehörige_zeilen = list(zip(*listen))
    #Formatstring rstellen mit der Join-Methode, gekoppelt mit der max() - und der range()-Funktion 
    formatstring = ' '.join(
            ['{:<%ds}'%(maxlength) for maxlength in [
                max([len(string) for string in zusammengehörige_zeilen[linenumber]])
                for linenumber in range(len(zusammengehörige_zeilen))]])
    #Ausgabe der formatierten Liste
    for liste in listen:
        print(formatstring.format(*liste))
Den Argparser und die gesamte Thematik dahinter werde ich versuchen, im Bootcamp nach der Klausur zu erlernen. Der entscheidende Code, den ich die ganze Zeit nicht selbst hingekriegt habe, ist der hier:

Code: Alles auswählen

  formatstring = ' '.join(
            ['{:<%ds}'%(maxlength) for maxlength in [
                max([len(string) for string in zusammengehörige_zeilen[linenumber]])
                for linenumber in range(len(zusammengehörige_zeilen))]])
Ich verstehe hier was die einzelnen Variablen bedeuten. Aber ich habe noch nicht gelernt, wie du all die Variablen mit for und in range() verbunden hast bzw. wie oder wo du die Syntax mit for und in range() gelernt hast. Dazu habe ich keine Schritt für Schritt Erklärung gefunden und wäre für eine Erklärung dankbar.

LG

Belal Ahmady
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Stichwort ist „list comprehension“ LC und die kann man auch verschachteln. Und man kann die auch „entschachteln“. Schau Dir LCs in der Dokumentation mal an und versuch mal den Ausdruck mit normalen Schleifen zu schreiben. Dann wird Dir der Zusammenhang vielleicht/hoffentlich klarer.

Vielleicht hilft es das erst einmal einfach etwas weniger kompakt zu formatieren:

Code: Alles auswählen

    formatstring = " ".join(
        [
            "{:<%ds}" % maxlength
            for maxlength in [
                max(
                    [
                        len(string)
                        for string in zusammengehörige_zeilen[linenumber]
                    ]
                )
                for linenumber in range(len(zusammengehörige_zeilen))
            ]
        ]
    )
Wobei ich die innerste wohl mit `map()` gelöst hätte:

Code: Alles auswählen

    formatstring = " ".join(
        [
            "{:<%ds}" % maxlength
            for maxlength in [
                max(map(len, zusammengehörige_zeilen[linenumber]))
                for linenumber in range(len(zusammengehörige_zeilen))
            ]
        ]
    )
Und das mit dem `for linenuber in range(len(…))`` ist ein „anti pattern“. Man kann direkt über die Elemente iterieren, ohne den Umweg über `linenumber`:

Code: Alles auswählen

    formatstring = " ".join(
        [
            "{:<%ds}" % maxlength
            for maxlength in [
                max(map(len, zeilen)) for zeilen in zusammengehörige_zeilen
            ]
        ]
    )
Dann stellt sich die Frage ob man den Ausdruck für die `maxlength`\s nicht einfach direkt ohne eine zwischengeschaltete LC berechnet:

Code: Alles auswählen

    formatstring = " ".join(
        [
            "{:<%ds}" % max(map(len, zeilen))
            for zeilen in zusammengehörige_zeilen
        ]
    )
Aus der LC könnte man noch einen Generatorausdruck machen und da braucht man dann die Klammern nicht mehr, weil man die vom `join()`-Aufruf ”mitbenutzen” kann:

Code: Alles auswählen

    formatstring = " ".join(
        "{:<%ds}" % max(map(len, zeilen)) for zeilen in zusammengehörige_zeilen
    )
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Antworten