Die häufigsten Zeichen eines Strings rausfinden

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
Sulex99
User
Beiträge: 5
Registriert: Freitag 20. Mai 2022, 15:43

Hey,

Bei einem Pythonkurs lautet die erste Aufgabe die wir programmieren müssen:
Schreiben Sie ein Python-Programm, das in einem gegebenen String s die drei am häufigsten in s vorkommenden Zeichen (außer Leerzeichen) identifiziert.
Die Ausgabe des Programms soll exakt diesem Muster folgen: Die drei häufigsten Zeichen sind ?, ? und ?.

Regeln
Beachten Sie bitte folgende Regeln und Einschränkungen: • Die erste Zeile des Programms muss die Definition der String-Variable s sein.
• Es dürfen nur Python-Features verwendet werden, die wir bereits durchgenommen haben (Operatoren, Variablen, Datentypen, Datenstrukturen, Kontrollstrukturen, Strings).
• Es dürfen keine Pakete importiert werden.
• Es dürfen keine Comprehensions verwendet werden. • Es dürfen keine in Python eingebaute Sortierfunktionen (wie z.B. sort oder sorted verwendet werden).
• Das Programm muss verständnisfördernd kommentiert sein.

So sieht mein Code aktuell aus:

s="Griechenland ist nicht klein".lower()
>>> d={}
>>> a=dict((c,s.count(c)) for c in s)
>>> a
{'g': 1, 'r': 1, 'i': 4, 'e': 3, 'c': 2, 'h': 2, 'n': 4, 'l': 2, 'a': 1, 'd': 1, ' ': 3, 's': 1, 't': 2, 'k': 1}
>>> max((k,j) for j,k in a.items())[1]
'n'
>>> del a['n']
>>> max((k,j) for j,k in a.items())[1]
'i'
>>> del a['i']
>>> max((k,j) for j,k in a.items())[1]
'e'
>>> x='n'
>>> y='i'
>>> z='e'
>>> print("Die drei häufigsten Zeichen sind {}, {} und {}".format(x,y,z))
Die drei häufigsten Zeichen sind n, i und e

Leider funktioniert das aber nur mit meinem String und nicht mit einem beliebigen :/
Gibt es eine Möglichkeit die Ausgabe der max-Funktion automatisch als Variable zu definieren oder sonst einen anderen Weg diese Aufgabe zu lösen?

Danke euch.
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

Du definierst s als Variable, d als Variable und a auch. Wo ist da das Problem, noch weitere zu definieren?
Variablennamen sollten übrigens aussagekräftig sein. Weder das vorgegebene s, noch a oder d sind das. Bei s muß man den Aufgabensteller verurteilen, bei allen anderen solltest Du bessere Namen finde, zum Beispiel counted_characters. Wenn Comprehensions verboten sind, dann vielleicht auch Generatorausdrücke. Warum auch immer jemand der Aufgaben für Python schreibt verbietet, Pythonausdrücke zu verwenden ...
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Interessanter Python Kurs, ist der öffentlich zugänglich (online) oder in einer Schule, etc?
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
Benutzeravatar
__blackjack__
User
Beiträge: 13006
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ich würde mal vermuten die Generatorausdrücke sind verboten, denn insbesondere bei der Definition von `a` wäre es sonst doch etwas unsinnig eine „dict comprehension“ zu verbieten, aber `dict()` aufrufen mit einem Generatorausdruck zu erlauben. Effizient ist es auch nicht a) für jedes Zeichen die Zeichenkette erneut zu durchlaufen, und vor allem auch für Zeichen die mehrfach vorkommen, jedes mal neu zu zählen. Das Ergebnis ist ja jedes mal das gleiche.

Und bei den `max()`-Aufrufen wäre es zumindest *etwas* effizienter wenn man die Tupel mit Anzahl und Zeichen nicht jedes mal aufbaut, sondern nur einmal und sich merkt.

Ein Punkt aus der Aufgabenstellung ist auch nicht umgesetzt, denn auch wenn man bei den meisten ”normalen” Zeichenketten vielleicht Glück hat und verhältnismässig wenig Leerzeichen vorkommen, so sollen die laut Aufgabenstellung explizit ausgeschlossen werden.

Und noch ein Randfall der hier nicht berücksichtigt wird: Was soll das Programm eigentlich machen falls weniger als drei verschiedene Zeichen (abzüglich Leerzeichen) in `s` vorkommen? Da ist auch die Aufgabenstellung unterspezifiziert, aber man kann eventuell damit Punkten wenn man sich entweder eine sinnvolle Behandlung überlegt und umsetzt, oder diesen Randfall zumindest geeignet dokumentiert.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Sulex99
User
Beiträge: 5
Registriert: Freitag 20. Mai 2022, 15:43

Sirius3 hat geschrieben: Freitag 20. Mai 2022, 19:04 Du definierst s als Variable, d als Variable und a auch. Wo ist da das Problem, noch weitere zu definieren?
Variablennamen sollten übrigens aussagekräftig sein. Weder das vorgegebene s, noch a oder d sind das. Bei s muß man den Aufgabensteller verurteilen, bei allen anderen solltest Du bessere Namen finde, zum Beispiel counted_characters. Wenn Comprehensions verboten sind, dann vielleicht auch Generatorausdrücke. Warum auch immer jemand der Aufgaben für Python schreibt verbietet, Pythonausdrücke zu verwenden ...
Ich denke das liegt daran, dass wir gerade erst angefangen haben mit dem Kurs. Dürften wir alles verwenden, könnten wir einfach andere Programme aus dem Internet kopieren.
Ich verstehe nicht ganz was mir hier weitere Variablen bringen sollen, da mit dem dict Befehl dann doch das gleiche rauskommt oder?
Die Bennenung kann ich noch anpassen, das war jetzt erstmal nur ein erster Versuch: :-)
Sulex99
User
Beiträge: 5
Registriert: Freitag 20. Mai 2022, 15:43

ThomasL hat geschrieben: Samstag 21. Mai 2022, 11:12 Interessanter Python Kurs, ist der öffentlich zugänglich (online) oder in einer Schule, etc?
Das ist ein Uni-Kurs, da kann man als Student teilnehmen. Ist freiwillig, aber bringt bei uns in den Naturwissenschaften bestimmt was nachher in der Arbeitswelt, mit Python umgehen zu können.
Sulex99
User
Beiträge: 5
Registriert: Freitag 20. Mai 2022, 15:43

__blackjack__ hat geschrieben: Samstag 21. Mai 2022, 12:17 Ich würde mal vermuten die Generatorausdrücke sind verboten, denn insbesondere bei der Definition von `a` wäre es sonst doch etwas unsinnig eine „dict comprehension“ zu verbieten, aber `dict()` aufrufen mit einem Generatorausdruck zu erlauben. Effizient ist es auch nicht a) für jedes Zeichen die Zeichenkette erneut zu durchlaufen, und vor allem auch für Zeichen die mehrfach vorkommen, jedes mal neu zu zählen. Das Ergebnis ist ja jedes mal das gleiche.

Und bei den `max()`-Aufrufen wäre es zumindest *etwas* effizienter wenn man die Tupel mit Anzahl und Zeichen nicht jedes mal aufbaut, sondern nur einmal und sich merkt.

Ein Punkt aus der Aufgabenstellung ist auch nicht umgesetzt, denn auch wenn man bei den meisten ”normalen” Zeichenketten vielleicht Glück hat und verhältnismässig wenig Leerzeichen vorkommen, so sollen die laut Aufgabenstellung explizit ausgeschlossen werden.

Und noch ein Randfall der hier nicht berücksichtigt wird: Was soll das Programm eigentlich machen falls weniger als drei verschiedene Zeichen (abzüglich Leerzeichen) in `s` vorkommen? Da ist auch die Aufgabenstellung unterspezifiziert, aber man kann eventuell damit Punkten wenn man sich entweder eine sinnvolle Behandlung überlegt und umsetzt, oder diesen Randfall zumindest geeignet dokumentiert.
Da ist unser erstes Programmaufgabe, deswegen habe ich noch nicht viel Ahnung von Python. Ich hatte keinen anderen Weg gefunden, um den zweit- und dritthäufigsten Buchstaben herauszufinden, ohne den häufigsten zu löschen.
"Und bei den `max()`-Aufrufen wäre es zumindest *etwas* effizienter wenn man die Tupel mit Anzahl und Zeichen nicht jedes mal aufbaut, sondern nur einmal und sich merkt." Könntest du das etwas genauer erläutern?
"Ein Punkt aus der Aufgabenstellung ist auch nicht umgesetzt, denn auch wenn man bei den meisten ”normalen” Zeichenketten vielleicht Glück hat und verhältnismässig wenig Leerzeichen vorkommen, so sollen die laut Aufgabenstellung explizit ausgeschlossen werden." Da habe ich absolut keine Ahnung welchen Befehl man dafür verwenden könnte.
Benutzeravatar
__blackjack__
User
Beiträge: 13006
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Sulex99: Werd als ersten Schritt mal die Generatorausdrücke los, denn wenn „comprehension“-Syntax nicht erlaubt ist, dann Generatorausdrücke sicher auch nicht. Denn sonst hätte man „comprehensions“ auch erlauben können. Dann siehst Du vielleicht auch einfacher wie man das mit den Leerzeichen löst, denn das ist letztlich nicht schwer, weil das zu den Grundlagen gehört was man so in Programmen mit dem Programmfluss machen kann: Bedingte Ausführung. Also den Schritt mit dem Zählen des Zeichens nur machen wenn er kein Leerzeichen ist. Wobei dieser Test am besten nicht mit einem literalen Leerzeichen gemacht wird, sondern mit einer Methode auf Zeichenketten.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Sulex99
User
Beiträge: 5
Registriert: Freitag 20. Mai 2022, 15:43

__blackjack__ hat geschrieben: Sonntag 22. Mai 2022, 13:25 @Sulex99: Werd als ersten Schritt mal die Generatorausdrücke los, denn wenn „comprehension“-Syntax nicht erlaubt ist, dann Generatorausdrücke sicher auch nicht. Denn sonst hätte man „comprehensions“ auch erlauben können. Dann siehst Du vielleicht auch einfacher wie man das mit den Leerzeichen löst, denn das ist letztlich nicht schwer, weil das zu den Grundlagen gehört was man so in Programmen mit dem Programmfluss machen kann: Bedingte Ausführung. Also den Schritt mit dem Zählen des Zeichens nur machen wenn er kein Leerzeichen ist. Wobei dieser Test am besten nicht mit einem literalen Leerzeichen gemacht wird, sondern mit einer Methode auf Zeichenketten.
ok ich habe jetzt den Code etwas verändert, er sieht jetzt so aus.

s = input("Geben Sie einen String ein: ")
s = s.lower()
zeichen = {}

for i in s:
if i not in zeichen and i != " ":
zeichen = 1
elif i != " ":
zeichen = zeichen + 1

häufigkeit = max(zeichen.values())
for x in zeichen:
if zeichen[x] == häufigkeit:
häufigstes = x
print("Das häufigste Zeichen ist {}. Es kommt {}-mal vor.".format(x, häufigkeit))

Leider funktioniert das aber nur für das häufigste Zeichen und nicht die 3 häufigsten :/

Was kann man da ändern, dass es doch noch geht?

Das habe ich jetzt so in Visual Studio Code probiert btw.
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

Benutze bitte code-Tags hier im Forum. Denn es geht nicht nur die Einrückung verloren sondern auch der Indexzugriff, so dass der Code, den du hier postest, nun brauchbar ist.
Deutsche Begriffe haben oft das Problem dass Singular und Plural gleichgeschrieben werden. Bei `zeichen` denke ich immer zuerst an ein Zeichen.
`i` ist ein sehr schlechter Variablenamen. Und warum nennst du dann dasselbe Ding später x?
Zum Finden des häufigsten Zeichens hattest du doch schon max mit items kombiniert gehabt. Warum hast du das geändert?
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Hier mal ohne Comprehensions und ohne Generatoren:

Code: Alles auswählen

#!/usr/bin/env python3

def get_counts(text):
    counts = {}
    for char in text.lower():
        if char.strip():
            counts[char] = counts.get(char, 0) + 1
    return counts

def get_most_commons(counts, n):
    most_commons = []
    while counts and len(most_commons) < n:
        most_commons.append(max(counts, key=counts.get))
        del counts[most_commons[-1]]
    return most_commons

def main():
    text = "Griechenland ist nicht klein"
    x, y, z = get_most_commons(get_counts(text), 3)
    print(f"Die drei häufigsten Zeichen sind {x}, {y} und {z}")

if __name__ == "__main__":
    main()
Der Fall von weniger als 3 Zeichen wird noch nicht abgedeckt bzw führt zu einem Fehler. Auch ist nicht definiert, was bei Häufigkeit 3x a und b, sowie 4x c und d passieren soll, wenn nur die 3 häufigsten gewünscht sind. Kommt dann a oder b mit rein...?
Benutzeravatar
__blackjack__
User
Beiträge: 13006
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@snafu: Das `strip()` finde ich als Test ein bisschen kryptisch wo Zeichenketten doch eine `isspace()`-Testmethode haben.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

__blackjack__ hat geschrieben: Montag 23. Mai 2022, 22:02 @snafu: Das `strip()` finde ich als Test ein bisschen kryptisch wo Zeichenketten doch eine `isspace()`-Testmethode haben.
Jepp, dachte ich mir später auch. Oder über split() gehen und eine innere Schleife bauen, wäre auch eine Möglichkeit.
Antworten