|
Aus dem OpenClipart-Project |
Das
„Name That Cow“-Problem klingt recht spannend, allerdings ist ein Problem, dass mir die Datentabelle mit den 5.000 „acceptable cattle names“ nicht zur Verfügung steht.
Problembeschreibung
Auf einer texanischen Rinderfarm soll für die Seriennummer einer Kuh eine Liste weiblicher Vornamen vorgeschlagen werden, wobei die Übersetzung sich am Tastenfeld eines Telefons orientiert, d. h. für die Zahl 2 kann im Vornamen der Buchstabe A, B oder C stehen.
Ich verwende meine Telefontastatur, wie ich sie auf meinem Telefon vorfinde.
1 |
2
ABC |
3
DEF |
4
GHI |
5
JKL |
6
MNO |
7
PQRS |
8
TUV |
9
WXYZ |
Diese Änderung sollte unproblematisch sein. Die richtige Funktionsweise meines Programms kann später über die Tastatur überprüft werden. Wirft mir das Programm für den Code 23353 z. B. den Vornamen Adele aus, dann kann ich prüfen, ob die Buchstaben jeweils in den den Zahlen zugeordneten Buchstabenlisten enthalten sind.
Folglich stellt sich folgendes Problem: Schreibe ein Programm das für die Nummer eines Rinds alle validen Namen ausgibt, die für diese Nummer generiert werden können. Sonst lautet die Ausgabe „No matching names found“. Seriennummern dürfen maximal 9 Zahlen lang sein. Das Programm endet, wenn eine 0 eingegeben wird.
Vorüberlegungen
Die Aufgabenstellung führt zu folgenden Vorüberlegungen:
- Die Seriennummer eines Rindes darf keine 0 oder 1 enthalten, weil ich diesen Ziffern keinen Buchstaben zuweisen kann.
Die Verwendung des RE-Moduls bietet sich m. E. an. Die dynamische Generierung eines RE-Ausdrucks ist m. E. erforderlich. (Ging einfacher)
- Möglicherweise macht es Sinn die Vornamen in Listen entsprechend der Länge aufzuteilen. Das könnte helfen die Performanz zu verbessern.
Datendatei aufbauen
Ich habe mir - leider manuell - aus der Wikipedia eine Liste mit - laut Wikipedia - 1.761 weiblichen Vornamen (Stand März 2013) geholt und aufbereitet. Aus dieser Liste soll das Programm geeignete Namen auswählen.
Die Vornamensliste wird aus dem Quelltext der Kategorienseiten heraus aufgebaut:
with open("Männlicher Vorname.txt") as f, open("Männliche Vornamen.txt","w") as g:
for line in f:
line = line.replace("\n","")
# title="Zsuzsanna"
if "title" in line:
line = line.split('title="')[1]
vorname = line.split('"')[0]
vorname = vorname.replace(" (Vorname)","")
vorname = vorname.replace(" (Name)","")
print(vorname)
vorname += "\n"
g.write(vorname)
Das war gerade etwas Handarbeit, aber noch im Rahmen und einfacher und schneller als sich beim
Pywikipediabot einzulesen.
Quelle:
Deutschsprachige Wikipedia (2. März 2013)
Die entsprechende Übersicht mit denn männlichen Vornamen bietet - laut Wikipedia - 3.390 männliche Vornamen (Stand März 2013).
Quelle:
Deutschsprachige Wikipedia (2. März 2013)
Aus beiden Listen kann man die benötigte Vornamensliste aufbauen.
Ein- und Ausgabe
Die Eingabe stellt man sich bei HP in etwa in folgender Form vor:
Program Input
232
252473
727225
0
Program Output
Possible names for #232 are: Ada
Possible names for #252473 are: Blaise, Claire
Possible names for #727225 are: Pascal
Sieht leistbar aus.
Mein Programm
Das re-Modul kommt hier nicht zum Einsatz, weil es Treffer für Strings findet, nicht aber in Listen. Eigentlich hätte ich gerne alle Listenelemente bekommen und muss daher - gefühlt - einen kleinen Umweg nehmen.
# Code wars IV
# Problem 9: Name That Cow
def codeliste_aufbauen(data):
''' Bekommt die Daten und gibt
einzelne Codes in einer Liste zurück
'''
data = data.replace(" ","")
data = data.split("\n")
if data[-1] == "0":
data.pop()
return data
def ergebnis_ausgeben(code,namensliste):
''' Erledigt die Ausgabe in der Konsole
'''
if namensliste: # Wahr, wenn die Liste nicht leer ist!
print("Possible names for #{} are: {}.\n".format(code,", ".join(namensliste)))
else:
print("No matching names found for #{}.\n".format(code))
def vornamenliste_aufbauen():
''' Holt sich die Daten aus den Vornamenslisten
Offene Probleme:
[ ] Es werden alle Namen geholt, nicht nur die, die
auch möglich sind, z. B. < 10 oder ohne Leerzeichen
und ohne Sonderzeichen
'''
vornamen = []
dateien = ["Männliche Vornamen.txt","Weibliche Vornamen.txt"]
for datei in dateien:
with open(datei) as f:
for line in f:
line = line.replace("\n","")
vornamen.append(line)
vornamen.sort()
# Trainingsmaterial
'''
Wähle code = 382 -> EVA
vornamen = ['Bob', 'Eda', 'Eda', 'Eka', 'Eka', 'Eva', 'Ewa', \
'Ida', 'Iga', 'Ina', 'Ina', 'Ira', 'Ira', 'Isa', \
'Isa', 'Iva', 'Lea', 'Lia', 'Mia', 'Nea', 'Nia', \
'Noa', 'Néa', 'Oda', 'Ola', 'Ola', 'Ona', 'Oya', \
'Pia', 'Ria', 'Rob', 'Uta']
'''
return vornamen
def treffer_suchen(code,vornamen):
''' Suche alle Treffer in der Vornamensliste für
den dekodierten code und gibt die Liste zurück
'''
codeliste = {"2":["A","B","C"],
"3":["D","E","F"],
"4":["G","H","I"],
"5":["J","K","L"],
"6":["M","N","O"],
"7":["P","Q","R"],
"8":["T","U","V"],
"9":["W","X","Y","Z"]}
results = [] # Nimmt die Ergebnisse auf
if "1" in code or "0" in code:
# Der 1 sind keine Buchstaben zugeordnet
return []
else:
for vorname in vornamen:
match = True
if len(vorname) != len(code):
# Kann nicht passen
pass
elif " " in vorname:
# Kann nicht passen
pass
else:
for letter, i in zip(list(vorname),list(code)):
if not letter.upper() in codeliste[i]:
match = False
# Muss nicht weiterprüfen
break
# Nächster Vorname!
if match == True:
results.append(vorname)
return results
def main():
""" Mainfunktion
"""
data = """114
2662
6886
42664
42662
58473
58472
5642662
382
232
252473
727225
6424235
0"""
# Übungsmaterial
# data = """382"""
# Daten aufbereiten
codes = codeliste_aufbauen(data)
vornamen = vornamenliste_aufbauen()
# Treffer suchen
for code in codes:
treffer = treffer_suchen(code,vornamen)
ergebnis_ausgeben(code,treffer)
if __name__ == "__main__":
main()
Zu verbessern wäre hier wohl die Funktion treffer_suchen(code,vornamen). Mich würde interessieren, ob es eine bessere Lösung - z. B. mittels Datenbank oder re-Modul geben könnte. Eine Musterlösung von HP gibt es für die frühen Code wars leider noch nicht.
Verbesserungsvorschläge und Feedback
Ich habe
im Python-Forum und zwar hier um Kritik gebeten und bekommen.