Nur noch bis heute: Arabische Zahlen in Römische Zahlen

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.
erdal93
User
Beiträge: 6
Registriert: Freitag 4. November 2016, 01:46

Hallo,

habe wieder eine Aufgabe mit der ich nicht weiter komme. Ich soll die vom Nutzer eingegebene Dezimalzahl zwischen 1 und 3999 in eine Dezimalzahl umwandeln. Dafür soll diese natürlich genau so aussehen wie wir sie heutzutage schreiben, heißt für eine 4 = IV etc.

Ich habe mich am Anfang erst mal darauf konzentriert, dass das Programm die einfachen römischen Zahlen erkennt, also 1, 5, 10, 50, 100, 500 und 1000. Da hatte ich am Anfang eine while Schleife gebaut die von 0 bis 4000 geht und bei den jeweiligen Zahlen stoppt. Nach etwas googeln habe ich das dann abgeändert.
So sieht es momentan bei mir aus (keine Ahnung ob das überhaupt richtig und gut gelöst ist)

Code: Alles auswählen

arabischeZahl = int(input ("Geben Sie eine Zahl zwische 1 und 3999 ein:"))
if arabischeZahl < 1 or arabischeZahl> 3999:
    print ("Ihre Eingabe ist ausserhalb des erlaubten Bereichs.")

roemischeZahl = ""

if arabischeZahl == 1000:
    print('Arabisch: 1000 = Römisch:', roemischeZahl + "M")
elif arabischeZahl == 900:
    print('Arabisch: 900 = Römisch:', roemischeZahl + "CM")
elif arabischeZahl == 500:
    print('Arabisch: 500 = Römisch:', roemischeZahl + "D")
elif arabischeZahl == 400:
    print('Arabisch: 400 = Römisch:', roemischeZahl + "CD")
elif arabischeZahl == 100:
    print('Arabisch: 100 = Römisch:', roemischeZahl + "C")
elif arabischeZahl == 90:
    print('Arabisch: 90 = Römisch:', roemischeZahl + "XC")
elif arabischeZahl == 50:
    print('Arabisch: 50 = Römisch:', roemischeZahl + "L")
elif arabischeZahl == 40:
    print('Arabisch: 40 = Römisch:', roemischeZahl + "XL")
elif arabischeZahl == 10:
    print('Arabisch: 10 = Römisch:', roemischeZahl + "X")
elif arabischeZahl == 9:
    print('Arabisch: 9 = Römisch:', roemischeZahl + "IX")
elif arabischeZahl == 5:
    print('Arabisch: 5 = Römisch:', roemischeZahl + "V")
elif arabischeZahl == 4:
    print('Arabisch: 4 = Römisch:', roemischeZahl + "IV")
elif arabischeZahl == 1:
    print('Arabisch: 1 = Römisch:', roemischeZahl + "I")
Der nächste Schritt wäre ja jetzt, dass ich die Eingabe so bearbeite, dass das Programm die Strings zusammenfügt, die es brauch und diese dann ausgibt. Hier kommt denke ich auch die Subtraktionsrege ins Spiel (worüber ich mich noch erst informieren muss). Ich wollte vorerst es aber schaffen, dass das Programm die "nicht einfachen" römischen Zahlen angibt. Sprich bei einer Eingabe von 2, dass dann eine Ausgabe von "II" kommt. Ich hab mir einiges ergooglet und auch viel identisches gesehen (in anderen Programmiersprachen). Doch ich komm einfach nicht drauf wie das funktionieren kann, dafür bin ich einfach noch zu unwissend. Hier im Forum gab es mal ein ähnliches Thema, welches ich mir auch durchgelesen habe doch auch das bringt mich nicht weiter.

Leider muss ich die Aufgabe abgeben und das auch noch heute um 16 Uhr. Mir bleiben also knapp 14 Stunden für diese Aufgabe. Hoffe ihr könnt mir helfen :)

Gruß
erdal93
Zuletzt geändert von Anonymous am Samstag 5. November 2016, 13:03, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
heiner88
User
Beiträge: 65
Registriert: Donnerstag 20. Oktober 2016, 07:29

Statt dem print-Statement, musst du den String noch zusammenfügen: roemischeZahl += "M"

Code: Alles auswählen


while arabischeZahl > 0:
    if  arabischeZahl >= 1000:
        arabischeZahl  -= 1000
        print('Arabisch:  1000 = Roemisch:', "M")
        
   ...
    elif arabischeZahl >= 1:
        arabischeZahl -= 1
        print('Arabisch:     1 = Roemisch:', "I")
        

nezzcarth
User
Beiträge: 1790
Registriert: Samstag 16. April 2011, 12:47

Hier gibt es gewiss mehrere Lösungen, wobei manche etwas aufwendiger sind als andere. Hast du dir mal divmod sowie Pythons Dictionary Datenstruktur angesehen?
erdal93
User
Beiträge: 6
Registriert: Freitag 4. November 2016, 01:46

Welche Lösungen meinst du? Ich habe diesbezüglich nichts gefunden. Die anderen beiden Sachen schau ich mir mal an, danke :)
Sirius3
User
Beiträge: 18335
Registriert: Sonntag 21. Oktober 2012, 17:20

@erdal93: Deine Aufgabe ist ja nicht, solange zu googeln, bis Du eine Lösung gefunden hast, die genau auf das Problem passt, sondern selbst etwas zu programmieren. Dazu mußt Du das Problem erst einmal in kleinere Teilprobleme aufspalten, wo die Lösung offensichtlich ist. Hier könntest Du zuerst Schritt für Schritt aufschreiben, wie Du eine Zahl händisch als römische Zahl ausrechnen würdest. Der Trick dabei ist ja, dass man jede Ziffer für sich betrachten kann, die Tausender, Hunderter, Zehner und Einer.
BlackJack

@erdal93: Zudem hat man bei einer ergoogleten Lösung dann ja das Problem, dass die zwar funktionieren mag, solange man aber nicht erklären kann *wie* sie funktioniert, hilft das nur solange bis man bei der Nachbesprechung die ergooglete Lösung vorstellen soll. Das Problem hat ein Kollege von Dir ja anscheinend gerade. ;-)
erdal93
User
Beiträge: 6
Registriert: Freitag 4. November 2016, 01:46

Welcher Kollege?

Also, da ich es in 3 Stunden abgeben muss, und ich noch weitere Aufgaben für die Uni hab, habe ich es mir erst Mal ergooglet. Klar, das hat wenig Sinn. Doch jede Lösung die ich gefunden habe hat nicht funktioniert, da entweder alte Python Version oder sonst was. Habe die Probleme beseitigt und auf mein Programm abgestimmt.

Zum eigentlichen Problem. Ich weiß nicht woran es liegt, aber ich hab mir soviel durchgelesen etc aber ich konnte das Problem nicht angehen. Ich kann mir das einfach nicht vorstellen wie es zu programmieren gilt, dass die Eingabe in einzelne Teile aufgeteilt , diese mit den römischen Zahlen abgeglichen und dem entsprechend wieder ausgegeben werden. Vielleicht war es gestern schon zu spät, oder ich brauch einfach eine Starthilfe bei sowas, dass das Denken für Derartiges erst aktiviert wird bei mir :D.
BlackJack

@erdal93: Hier gab's die Woche schon einen anderen, neuen Benutzer der sich (und uns) gefragt hat wie eine im Netz gefundene Umrechnungsfunktion eigentlich zu verstehen ist. Ich vermute mal das ist kein Zufall, sondern jemand mit den gleichen Hausaufgaben.

In Teile aufteilen muss man die Eingabe ja eher in der Gegenrichtung: Römische → arabische Darstellung.

Dein Ansatz ist zwar recht ausufernd geschrieben, weil Du da so viele ``if``-Zweige hast, die im Grunde gleich sind und sich nur durch die römische Ziffer und deren Zahlwert unterscheiden, aber grundsätzlich schon mal nicht falsch. Wie heiner88 angemerkt hat, müsstest Du Dir die einzelnen römischen Teile merken, damit Du die am Ende der Schleife noch hast. Also entweder so wie von ihm vorgeschlagen gleich zu einer Ergebniszeichenkette hinzufügen, oder die Teile in einer Liste sammeln und am Ende der Funktion mit Hilfe der `join()`-Methode auf Zeichenketten zusammenfügen. Was Du da machst ist ja immer die leere Zeichenkette, die Du an `roemischeZahl` gebunden hast mit dem Teilergebnis zu verbinden und auszugeben. Aber Du merkst Dir das nirgends, also ist `roemischeZahl` überflüssig, denn es ändert sich nie, das ist immer die leere Zeichenkette. Und ``'' + irgend_eine_zeichenkette`` ist eine Operation als würde man ``0 + irgend_eine_zahl`` schreiben. '' ist bezogen auf Zeichenkettenverkettung der neutrale Wert.

Noch ein kleiner Tipp zu Vergleichsoperatoren: Python hat da eine Syntaxregel die das Verketten erlaubt. ``a op1 b op2 c`` mit `op1` und `op2` aus der Menge der Vergleichoperatoren ist das gleiche wie ``a op1 b and b op2 c``. Das heisst Bereichsabfragen kann man wie in der Mathematik ausdrücken: ``if not 1 <= arabische_zahl < 4000: …``. Das liest sich oft leichter, eben weil man das aus der Mathematik kennt. 4000 habe ich diesem Beispiel statt 3999 gewählt, um zu zeigen das die beiden Operatoren nicht gleich sein müssen.
nuhakan
User
Beiträge: 51
Registriert: Donnerstag 11. August 2016, 11:42

Hallo,

ich soll diese Aufgabe nicht lösen, aber versuche es. :)

Erst mal der Anfang meines Codes.

Code: Alles auswählen

arabischeZahl = int(input ("Geben Sie eine Zahl zwischen 1 und 3999 ein: "))

if arabischeZahl < 1 or arabischeZahl > 3999:
    for i in range(0, 2):
        print ("Ihre Eingabe ist ausserhalb des erlaubten Bereichs.")
        arabischeZahl = int(input ("Geben Sie eine Zahl zwischen 1 und 3999 ein: "))
        import sys
        sys.exit("This is the End")

        if arabischeZahl > 0 or arabischeZahl <= 3999:
            break
Es funktioniert nicht wie ich will. Der User darf 3 mal falsch machen. Wenn die Nummer richtig ist, geht. Wenn es falsch ist, geht den Loop mit zwei Versuchen weg. Ich glabube, dass das Problem die Zeile 10 ist. Diese Zeile ist da, weil der User eine richtige Nummer in zweiten Versucht geben könnte.

Der Rest meines Codes bzw. meiner Idee.

Code: Alles auswählen

romZahl = {
"M" : 1000,
"CM" : 900,
"D"	: 500,
"CD" : 400,
"C"	: 100,
"XC" : 90,
"L"	: 50,
"XL" : 40,
"X"	: 10,
"IX" : 9,
"V"	: 5,
"IV" : 4,
"I"	: 1
}

ergebnis = ""

for i in romZahl:
    while romZahl.values() <= arabischeZahl:
        ergebniss += romZahl.keys()
        arabischeZahl -= romZahl.values()
print ("ergebniss")
Ich habe im Google gesucht, wie man die römischen Nummern aufgebaut werden und die Tabelle, die ich in der Dictonary reingetan habe, gefunden. Das ist eigentlich ein Trick, weil die Tabelle besonders für diesem Fall konzipiert ist. Die Idee dahinter ist, wenn man eine Nummer bekommt z.B. 1.200, sollte es mit dem höchsten Wert der Tabelle erfüllen. Im diesen Fall "M". Bleiben 200. Jetzt ist "C" der höchste Wert. Bleiben 100 und wird wieder mit "C" erfüllt. Ergebnis: "MCC".

Ich glaube, dass die Lösung ein While-Loop sein muss. Aber das Problem hier ist, wie ich mit der Tabelle arbeite. Ist die Dictionary eine gute Idee? Im Loop soll einerseits die römischen Buchstabe addieren werden und anderseits die arabische Zahlen abziehen werden.

Ich möchte wissen, ob meine Idee geht oder nicht.
BlackJack

@nuhakan: Zum ersten Quelltext: Versuche Wiederholungen von Code und Daten zu vermeiden. Das macht Programme fehleranfällig gegenüber Veränderungen und Fehlerbehebungen, weil man dann immer an mehreren Stellen Code oder Daten anpassen muss, und keine Stelle vergessen darf, und aufpassen muss, dass man jede Stelle gleichartig ändert.

Abfragen der Zahl vom Benutzer und testen auf den Wertebereich sollte man in dem Code nur *einmal* schreiben. Und zwar am Anfang der Schleife. Die kann man dann (vorzeitig) verlassen wenn die Eingabe erfolgreich war.

Importe gehören an den Anfang des Moduls, damit man sieht wovon das Modul abhängig ist und wo welcher Name herkommt.

`sys.exit()` sollte man sehr sparsam anwenden. Eigentlich würde man für diese Benutzereingabe eine Funktion schreiben und Funktionen sind schlecht flexibel (wieder)verwendbar wenn sie einfach so den gesamten Prozess beenden. An der Stelle würde man entweder einen Rückgabwert verwenden der anzeigt, dass keine Eingabe erfolgte (`None` zum Beispiel) oder eine Ausnahme auslösen.

Wenn der Benutzer es dreimal falsch machen darf, dann sollte die ``for``-Schleife nicht nur zweimal durchlaufen werden. → ``range(3)``.

Die Namensschreibweise orientiert sich nicht am Style Guide for Python Code. `arabischeZahl` sollte `arabische_zahl` heissen, oder einfach nur `zahl`, denn da ist im Computer nichts arabisches dran. Intern wird die ziemlich wahrscheinlich in einer Binärdarstellung repräsentiert.

Das Wörterbuch im zweiten Quelltext ist keine gute Idee weil ausser in der letzten Python 3-Version Wörterbücher ungeordnet sind, bei Deiner (an sich richtigen) Idee aber die Reihenfolge eine Rolle spielt. Für das umwandeln einer Zahl in eine Darstellung mit römischen Zahlzeichen ist die eigenschaft das man einen Schlüssel auf einen Wert abbilden kann, auch gar nicht relevant. Wörterbuch macht also keinen Sinn. Eine Sequenz mit den Schlüssel/Wert-Paaren, also beispielsweise eine Liste mit Tupeln, würde völlig ausreichen.

Der Rest scheint geraten und nicht ausprobiert zu sein, denn dann wüsstest Du ja schon dass das zu Ausnahmen führt. Die Bedingung der ``while``-Schleife geht in Python 3 nicht, weil die beiden Werte nicht auf diese Weise vergleichbar sind, weil es auch gar keinen Sinn macht die Menge der Schlüssel mit einer Zahl zu vergleichen. Und in Python 2 würde dann spätestens Zeile 21 zu einer Ausnahme führen weil die Addition von Zeichenketten und Listen keinen Sinn macht und deshalb auch nicht implementiert ist.
nuhakan
User
Beiträge: 51
Registriert: Donnerstag 11. August 2016, 11:42

BlackJack hat geschrieben:Wenn der Benutzer es dreimal falsch machen darf, dann sollte die ``for``-Schleife nicht nur zweimal durchlaufen werden. → ``range(3)``.
Die Idee war so, dass die Zeile 1 schon ein Versucht ist. Wenn der erste Versucht falsch ist, dann rein in die Schleife und noch zweimal. Aber schaffe ich nicht zu springen, wenn der erste Versucht falsch ist aber der zweite richtig.

Aber gut, mit Deinem Hinweis merke ich, dass mein Code doof ist.
BlackJack hat geschrieben:Der Rest scheint geraten und nicht ausprobiert zu sein, denn dann wüsstest Du ja schon dass das zu Ausnahmen führt. Die Bedingung der ``while``-Schleife geht in Python 3 nicht, weil die beiden Werte nicht auf diese Weise vergleichbar sind, weil es auch gar keinen Sinn macht die Menge der Schlüssel mit einer Zahl zu vergleichen. Und in Python 2 würde dann spätestens Zeile 21 zu einer Ausnahme führen weil die Addition von Zeichenketten und Listen keinen Sinn macht und deshalb auch nicht implementiert ist.
Ich habe versucht den Code auszuprobieren. Natürlich geht nicht, weil unterschiedliche Werte sind -schon bemerkt-. Ich dachte, dass es vielleicht die Werte irgendwie umtauschen dürften. So wie bei "2" und "2.0".

Danke für die Hinweise und Korrekturen. Ab morgen versuche etwas anders. ;)
heiner88
User
Beiträge: 65
Registriert: Donnerstag 20. Oktober 2016, 07:29

@BlackJack:
> Das Wörterbuch im zweiten Quelltext ist keine gute Idee weil ausser in der letzten Python 3-Version Wörterbücher ungeordnet sind

In Python 3.5 sind "dict" immer noch ungeordnet. Oder meinst du nächste Version 3.6 ?
BlackJack

@heiner88: Ah, ich hatte nur mitbekommen das `dict`\s geordnet werden, dachte das wäre schon aktuell.
heiner88
User
Beiträge: 65
Registriert: Donnerstag 20. Oktober 2016, 07:29

Danke für den Hinweis.

Code: Alles auswählen

from collections import OrderedDict

print('Regular dictionary:')
d = {}
d['a'] = 'A'
d['b'] = 'B'
d['c'] = 'C'
d['d'] = 'D'
d['e'] = 'E'

for k, v in d.items():
    print(k, v)

print('\nOrderedDict:')
d = OrderedDict()
d['a'] = 'A'
d['b'] = 'B'
d['c'] = 'C'
d['d'] = 'D'
d['e'] = 'E'

for k, v in d.items():
    print(k, v)
Mit Python 3.5.2 (ungeordnet):
[codebox=text file=Unbenannt.txt]
Regular dictionary:
a A
b B
e E
c C
d D

OrderedDict:
a A
b B
c C
d D
e E[/code]


Mit Python 3.6.0b3 (geordnet):
[codebox=text file=Unbenannt.txt]
Regular dictionary:
a A
b B
c C
d D
e E

OrderedDict:
a A
b B
c C
d D
e E[/code]
sebastian0202
User
Beiträge: 168
Registriert: Montag 9. Mai 2016, 09:14
Wohnort: Berlin

Mein Versuch in Python2.6

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

def get_value(regel, roemisch):
    zahl = 0
    if len(regel) == 1:
        return roemisch[regel]
    else:
        return roemisch[regel[1]] - roemisch[regel[0]]

def get_roemisch(zahl):
    roemisch = {'M':1000, 'D':500, 'C':100, 'L':50, 'X':10, 'V':5, 'I':1}
    regeln = ['M', 'CM', 'D', 'CD', 'C', 'XC', 'L', 'XL', 'X', 'IX', 'V', 'IV', 'I']
    text = ''

    for regel in regeln:
        val = get_value(regel, roemisch)
        while zahl >= val:
            text += regel
            zahl = zahl - val
    return text
def main():
    while 1:
        try:
            zahl = int(raw_input('Geben Sie eine Zahl ein: '))
            break
        except ValueError:
            print "War keine Zahl, nochmal."

    text = get_roemisch(zahl)
    print "Roemisch: %s" % (text)

if __name__ == '__main__':
    main()
Zuletzt geändert von sebastian0202 am Dienstag 8. November 2016, 10:53, insgesamt 2-mal geändert.
BlackJack

@sebastian0202: Da wird immer None ausgegeben.
sebastian0202
User
Beiträge: 168
Registriert: Montag 9. Mai 2016, 09:14
Wohnort: Berlin

Hab die Funktion get_roemisch erst im Onlineeditor erstellt und natürlich die return Anweisung vergessen :lol:
heiner88
User
Beiträge: 65
Registriert: Donnerstag 20. Oktober 2016, 07:29

Super Leistung.
Hier ist eine Alternative (die ist weder besser noch schlechter als deine Lösung):

Code: Alles auswählen

#python3
def int_to_rom(zahl):
    rom = ''
    while zahl > 0:
        if   zahl >= 1000: zahl -= 1000; rom += 'M'
        elif zahl >= 900:  zahl -= 900;  rom += 'CM'
        elif zahl >= 500:  zahl -= 500;  rom += 'D'
        elif zahl >= 400:  zahl -= 400;  rom += 'CD'
        elif zahl >= 100:  zahl -= 100;  rom += 'C'
        elif zahl >= 90:   zahl -= 90;   rom += 'XC'
        elif zahl >= 50:   zahl -= 50;   rom += 'L'
        elif zahl >= 40:   zahl -= 40;   rom += 'XL'
        elif zahl >= 10:   zahl -= 10;   rom += 'X'
        elif zahl >= 9:    zahl -= 9;    rom += 'IX'
        elif zahl >= 5:    zahl -= 5;    rom += 'V'
        elif zahl >= 4:    zahl -= 4;    rom += 'IV'
        elif zahl >= 1:    zahl -= 1;    rom += 'I'
    return rom

zahl = int(input('Geben Sie eine Zahl ein: '))
print(int_to_rom(zahl))
Zuletzt geändert von heiner88 am Dienstag 8. November 2016, 12:25, insgesamt 1-mal geändert.
heiner88
User
Beiträge: 65
Registriert: Donnerstag 20. Oktober 2016, 07:29

Oder noch eine andere Alternative:

Code: Alles auswählen

#python3
def int_to_rom(zahl):
    map = [(1000,'M'), (900,'CM'), (500,'D'), (400,'CD'), (100,'C'), (90,'XC'), 
           (50,'L'), (40,'XL'), (10,'X'), (9,'IX'), (5,'V'), (4,'IV'), (1,'I')]
    rom = ""
    for int, char in map:
        cnt   = zahl // int
        zahl -= int  * cnt
        rom  += char * cnt
    return rom

zahl = int(input('Geben Sie eine Zahl ein: '))
print(int_to_rom(zahl))
BlackJack

@heiner88: Also ich finde die Variante mit den vielen ``if`` schon schlechter weil dort Daten umständlich als Code ausgedrückt sind und das alles nach kopieren, einfügen, und leicht anpassen aussieht, was immer ein Warnzeichen sein sollte. Zudem ist die ”hübsche” Formatierung ”unpythonisch”.

Bei der letzten Variante wird die `map`-Funktion und der `int`-Typ verdeckt, bei `count` fehlt das `ou`, und `char` ist unpassend weil da auch Werte dran gebunden werden die aus mehr als einem „character“ bestehen. `rom` sollte wohl auch ein längerer Name sein.
Antworten