römische Zahlen vergleichen

Boje

Mitglied
Hallo zusammen!
Ich habe eine Klasse geschrieben, die das Comparable-Interface implementiert.

Der Vergleich soll über die Instanzvariable "klasse" geschehen, die folgende Werte annehmen kann: "Ia", "Ib", "IIa", "IIb", "IIIa", "IIIb", "IV", "V", "VI"

Da String ja die natürliche Ordnung implementiert hat müsste meiner Meinung nach folgendes gelten: "Ia" < "Ib" < "IIa" < "IIb" < "IIIa" < "IIIb" < "IV" < "V" < "VI".

Ich möchte das ganze dann über einen Bubblesort sortieren.

Hier mein Code:
Java:
class Baumstamm
implements Comparable<Baumstamm>
{
	private int nr;
	private double länge;
	private double durchmesser;
	private String klasse;
	private String güteKlasse;
	private double festmeter;
	
	public Baumstamm(int nr, double länge, double durchmesser, String klasse, String güteKlasse)
	{
		this.nr = nr;
		this.länge = länge;
		this.durchmesser = durchmesser;
		this.klasse = klasse;
		this.güteKlasse = güteKlasse;
		festmeter =  Math.round(Math.PI/4*durchmesser*länge*100)/100.;
	}
	
	public String getKlasse()
	{
		return klasse;
	}
	
	public int compareTo(Baumstamm b)
	{
		int i;
		if((this.getKlasse()).compareTo(b.getKlasse()) == 1)
			i = 1;
		if((this.getKlasse()).compareTo(b.getKlasse()) == -1)
			i = -1;
		else
			i = 0;
		return i;
	}
}

Bubblesort:
Java:
public void sort(Baumstamm[] arr) 
	{
		boolean vertauscht = false; 
	
			for(int i = 1; i < arr.length; i++)
			{
				if(arr[i-1].compareTo(arr[i]) == 1)
				{
					Baumstamm temp = arr[i];
					arr[i] = arr[i-1];
					arr[i-1] = temp;
					vertauscht = true;
				}
			}	
			
			if(vertauscht == true)
			{
				sort(arr);
			}	
	}

Mein Hauptprogramm:
Java:
public class Holzliste
public static void main(String[] args) 
	{
		Baumstamm b1 = new Baumstamm(1, 4, 2, "IIa", "A");
		Baumstamm b2 = new Baumstamm(1, 4, 2, "Ia", "A");
		
		System.out.println(b1.compareTo(b2));
	}

Doch es kommt nie der richtige Wert beim compareTo raus... Ich weiß nicht wo hier der Fehler ist.
Bei b1.compareTo(b2) kommt z.B. 0 heraus.

Es wäre schön, wenn mir jemand helfen kann 🙂
 
Zuletzt bearbeitet von einem Moderator:
Erstens verstehe ich nicht, wieso du das Rad neu erfindest.
Du könntest einfach das Interface Comparable implementieren und für Sortierungen gibts in der Standardlibrary genug Sachen (Arrays.sort, Collections.sort etc.)

Dein String besteht aus Zeichen und du willst Zeichen miteinander vergleichen. Dass "IIa" < "Ia" ist somit wohl klar (der ASCII-Wert von Großbuchstaben ist immer kleiner als von Kleinbuchstaben). Du müsstest deine römischen Zahlen zuerst in arabische Zahlen (Stichwort Integer) umwandeln und so vergleichen. Falls ein Rest (a, b etc.) bleibt, müsstest du noch einen String-Vergleich durchführen.

Java:
public int compareTo(Baumstamm b) {
    int i;
    Integer thisZahl = parseRoemischeZahl(this.getKlasse());
    Integer bZahl = parseRoemischeZahl(b.getKlasse());
    i = thisZahl.compareTo(bZahl);
    if(i == 0){
        int thisLength = getKlasse().length();
        int bLength = getKlasse().length();
        i = getKlasse.substring(thisLength-1, thisLength).compareTo(getKlasse.substring(bLength-1, bLength));
    }
    return i;
}
Das ist nur ein Ansatz, den Code müsstest du noch anpassen (erkennen, ob letztes Zeichen römische Zahl ist oder nicht; String aufteilen in 1. Teil [römische Zahl] und 2. Teil [a, b...])
 
Zuletzt bearbeitet:
Ich denke, das Problem liegt in deiner compareTo-Methode. Du greifst auf String.compareTo zurück. Das ist ok. Aber laut API-Doc liefert compareTo nicht notwendigerweise -1/0/1 sondern beliebige Werte die kleiner als 0, gleich 0 oder größer als 0 sind. Willst du weiterhin mit -1/0/1 rechnen, müsstest du das entsprechend zuordnen. Ich schreibe meinen Code in solchen Fällen lieber gleich so, dass ich auf größer/kleiner/gleich 0 prüfe.
 
Hallo Boje,

bei Deiner compareTo(...) Überschreibung
prüft Du ob compareTo() der String-Klasse (denn, Du rufst compareTo auf einem String!) genau 1 zurückgibt

Java:
if((this.getKlasse()).compareTo(b.getKlasse()) == 1)

Das wird wohl schiefgehen, denn in der API steht

Returns:
the value 0 if the argument string is equal to this string; a value less than 0 if this string is lexicographically less than the string argument; and a value greater than 0 if this string is lexicographically greater than the string argument.


von genau gleich 1 ist da nicht die Rede.

Gruß
tsitra
 
Ist das dann die richtige Lösung?

Java:
public int compareTo(Baumstamm b)
	{
		int i;
		if((this.getKlasse()).compareTo(b.getKlasse()) < 1 && (this.getKlasse()).compareTo(b.getKlasse()) > 0)
			i = 1;
		if((this.getKlasse()).compareTo(b.getKlasse()) > -1 && (this.getKlasse()).compareTo(b.getKlasse()) < 0)
			i = -1;
		else
			i = 0;
		return i;
	}


Java:
Baumstamm b1 = new Baumstamm(1, 4, 2, "IIa", "A");
Baumstamm b2 = new Baumstamm(1, 4, 2, "Ia", "A");
		
System.out.println(b1.compareTo(b2));

Das ergibt bei mir nämlich wieder 0, auch mit der neuen Lösung...

@Mujahiddin: Aber Ia steht doch lexikalisch weiter vorne als Ib und als IIa, und IIa steht weiter vorne als IIb und weiter hinten als Ib, deswegen verstehe ich das mit den römischen Zahlen nicht so recht...

und meine neue Methode zu sortieren ist jetzt folgende:
Java:
public void sort(Baumstamm[] arr) 
	{
		Arrays.sort(arr);
	}
 
Zuletzt bearbeitet:
Nee, jetzt bist du wohl etwas von der Rolle.
Sowas wie
Java:
if(x < 1 && x > 0) {/* ... */}
ist zumindest für int unsinnig.
Du solltest sowas wie
Java:
public int compareTo(Baumstamm b)
    {
        int i;
        if(this.getKlasse().compareTo(b.getKlasse()) > 0)
            i = 1;
        if(this.getKlasse().compareTo(b.getKlasse()) < 0)
            i = -1;
        else
            i = 0;
        return i;
    }
machen.

Alternativ (wie ich oben schonmal angedeutet hatte) kann man auch die Zuordnung von -1/0/1 ganz sein lassen und das so machen:
Java:
public int compareTo(Baumstamm b)
    {
        return this.getKlasse().compareTo(b.getKlasse());
    }
Dann müsstest du dein Methode sort(Baumstamm[] arr) allerdings auch ändern und statt '== 1' besser '> 0' testen.
Wenn du Arrays.sort() verwendest, sollten beide Varianten funktionieren.
 
Also deine Erklärung gibt für mich schon Sinn, aber trotzdem bekomme ich permanent 0 heraus...

Sowohl für diesen Code:
Java:
public int compareTo(Baumstamm2 b)
	{
		return this.getKlasse().compareTo(b.getKlasse());
    }

als auch hier:
Java:
public int compareTo(Baumstamm b)
{
        int i;
        if(this.getKlasse().compareTo(b.getKlasse()) > 0)
            i = 1;
        if(this.getKlasse().compareTo(b.getKlasse()) < 0)
            i = -1;
        else
            i = 0;
        return i;
}


Java:
public static void main(String[] args) 
{

		Baumstamm b1 = new Baumstamm(1, 4, 2, "IIa", "A");
		Baumstamm b2 = new Baumstamm(1, 4, 2, "Ia", "A");
		
		System.out.println(b1.compareTo(b2));
	}

auf der Konsole steht immer 0, egal ob b1.compareTo(b2) oder b2.compareTo(b1)... ;(
 
das in deinem ersten Programm 0 rauskommt ist nachvollziebar,
die anderen zuletzt genannten Varianten nicht unbedingt, besonders
> return this.getKlasse().compareTo(b.getKlasse());
müsste klar funktionieren, wenn nicht die Strings eben gleich sind,
vollständige Programme würden jeweils klarer sein

Fehler:
genau auf 1 getestet, das wurde ja schon angesprochen, > 0 usw.

und noch aktuell:
if (x) ..
if (y) ..
else ..

wenn x erfüllt ist, wird dieses if durchgeführt, aber auch vom nächsten if entweder der Normal- oder der else-Fall,
da es der Normalfall y nicht sein wird, kommt also das else mit "i = 0;" drann wenn die Bedingung x erfüllt ist,
korrekt laufet der Code


if (x) ..
else if (y) ..
else ..


bzw. einfach
> return this.getKlasse().compareTo(b.getKlasse());
 
Hm, also wenn ich deine Baumstamm-Klasse mit der berichtigten compareTo-Methode und der Beispiel-main laufen lasse, bekomme ich -1 ausgegeben. Vielleicht hast du noch irgendwo einen Tippfehler drin. Gib z.B. mal in deiner compareTo-Methode die beiden Werte aus, die du vergleichst, um zu sehen, ob die wirklich verschieden sind:
Java:
public int compareTo(Baumstamm b)
    {
        System.out.println("this=" + this.getKlasse() + ", b=" + b.getKlasse());
        // ... weiter wie gehabt
    }
 
Also es funktioniert, dennoch ist die Sortierung
VI < V < Ib < Ia < IV < IIb < IIa < IIIb < IIIa

Kann mir das noch jemand erklären?

Eigentlich kommt doch ein I vor einem V im Alphabet? Deswegen dachte ich, dass folgendes herauskommen müsste:
Ia < Ib < IIa < IIb < IIIa < IIIb < IV < V < VI
 
poste doch ein aktuelles Beispiel mit der aktuellen compare-Methode und passenden Testdaten in der main
 
Java:
public void sort(Baumstamm[] arr) 
    {
        boolean vertauscht = false; 
    
            for(int i = 1; i < arr.length; i++)
            {
                if(arr[i-1].compareTo(arr[i]) == 1)
                {
                    Baumstamm temp = arr[i];
                    arr[i] = arr[i-1];
                    arr[i-1] = temp;
                    vertauscht = true;
                }
            }   
            
            if(vertauscht == true)
            {
                sort(arr);
            }   
    }
Dein Sortieralgorithmus sortiert absteigend.
Wenn du aufsteigend sortieren willst, musst du die 1 in
Code:
iff(arr[i-1].compareTo(arr[i]) == 1)
mit -1 ersetzen.

Und wie gesagt kennt dein Programm keine römischen Zahlen. Du musst einen Parser schreiben!!!

Außerdem ist der Code deiner compareTo-Methode unnötig aufwendig. Dass du zweimal die compareTo-Methode anwendest, ist sinnlos. Entweder mach
Code:
return getKlasse().compareTo(b.getKlasse());
oder
Java:
int c = getKlasse().compareTo(b.getKlasse());
if( c < 0 ) return -1;
if( c > 0 ) return 1;
return 0;
 
Zuletzt bearbeitet:
Das aktuelle Beispiel und die Testdaten sind:

Klasse:
Java:
class Baumstamm
implements Comparable<Baumstamm>
{
	private int nr;
	private double länge;
	private double durchmesser;
	private String klasse;
	private String güteKlasse;
	private double festmeter;

	public Baumstamm(int nr, double länge, double durchmesser, String klasse, String güteKlasse)
	{
		this.nr = nr;
		this.länge = länge;
		this.durchmesser = durchmesser;
		this.klasse = klasse;
		this.güteKlasse = güteKlasse;
		festmeter =  Math.round(Math.PI/4*durchmesser*länge*100)/100.;
	}

	public String getKlasse()
	{
		return klasse;
	}

	public int compareTo(Baumstamm b)
	{
		return this.getKlasse().compareTo(b.getKlasse());
	}
}


Sortieren:
Java:
public void sort(Baumstamm[] arr) 
	{
		Arrays.sort(arr);
	}

Und die Testfälle sind
Java:
main(...)
Baumstamm b1 = new Baumstamm(1, 5, 0.25, Ia, A);
Baumstamm b2 = new Baumstamm(2, 5, 0.25, IIb, A);
Baumstamm b3 = new Baumstamm(3, 5, 0.25, IIa, A);
Baumstamm b4 = new Baumstamm(4, 5, 0.25, Ib, A);
Baumstamm b5 = new Baumstamm(5, 5, 0.25, IV, A);
Baumstamm b6 = new Baumstamm(6, 5, 0.25, IIIa, A);
Baumstamm b7 = new Baumstamm(7, 5, 0.25, IIIb, A);
Baumstamm b8 = new Baumstamm(8, 5, 0.25, V, A);
Baumstamm b9 = new Baumstamm(9, 5, 0.25, VI, A);
Baumstamm b10 = new Baumstamm(10, 5, 0.25, IIa, A);

und heraus kommt folgende Ordnung VI < V < Ib < Ia < IV < IIb < IIa = IIa < IIIb < IIIa

@Mujahiddin:
Ich verstehe nicht warum ich die römischen Zahlen parsen muss. Mir reicht es doch hier nach dem Alphabet zu sortieren und nicht nach den Zahlen, weil hier stimmt ja das Alphabet überein, oder?
I ist ja weiter vorne im Alphabet als V und a ist auch vor b. Deswegen dachte ich die ganze Zeit ein parsen der römischen ist nicht nötig...
 
wann wird die sort-Methode aufgerufen, was sind V, VI usw. in der main, Konstanten, Anführungszeichen weggelassen?

kann man sicher alles ergänzen, mache ich vielleicht noch alsbald, da mich der Fehler interessiert,
aber eigentlich auch nicht zuviel verlangt, ein lauffähiges Programm zur Verfügung zu stellen, oder?


edit:
von unten:
> Wenn ich das mache, dann sortiert dein Code so, wie man es erwartet:
> Ausgabe:
> IIIa IIIb IIa IIa IIb IV Ia Ib V VI

das ist wirklich immer wieder zu erleben, zum Glück mir erspart,
unverständlich wie sorglos manche mit der Zeit anderer umgehen..
 
Zuletzt bearbeitet von einem Moderator:
Dein Testcode dürfte gar nicht fehlerfrei kompilieren. Die Strings musst du in Anführungszeichen setzen:
Java:
Baumstamm b1 = new Baumstamm(1, 5, 0.25, "Ia", "A");
statt
Java:
Baumstamm b1 = new Baumstamm(1, 5, 0.25, Ia, A);
usw.

Wenn ich das mache, dann sortiert dein Code so, wie man es erwartet:

Ausgabe:
IIIa IIIb IIa IIa IIb IV Ia Ib V VI
 
Ja sorry, die Anführungszeichen hab ich vergessen, da die Daten über Swing rausgenommen werden und ich nur schnell ein BSP gemacht habe.

Aber auch bei euch wird doch der Fehler angezeigt.

ein Ia müsste doch vor einem IIIa stehen, weil a kommt doch vor I. Und warum stehen V und VI ganz am ganz am Ende, bei dieser Reihenfolge gehört es doch an den Anfang...

Warum erwartet man das so?
Ausgabe:
IIIa IIIb IIa IIa IIb IV Ia Ib V VI

ich würde es so erwarten:

VI V IV IIIb IIIa IIb IIa Ib Ia bzw genau anders rum, je nachdem ob absteigend oder aufsteigend... oder nicht? Vielleicht hab ich ja auch ein Problem mit Deutsch, aber dann wäre es schön, wenn ihr mich kurz aufklärt 😀

Edit:
Ich verdeutliche MEINE Überlegung nochmal

Sortierung 1. Buchstabe

I(a,b Ia, Ib, IIa, IIb V) V(x, I)

2.Buchstabe
Ia, Ib, II(a, b, Ia, Ib) IV, V, VI

3. Buchstabe
Ia, Ib, IIa, IIb, III(a,b) IV, V, VI

4. Buchstabe
Ia, Ib, IIa, IIb, IIIa, IIIb, IV, V, VI
 
Zuletzt bearbeitet:
keine Ahnung was Fant erwartet, aber als Otto-Normal-User würde ich auch deine Variante erwarten, zumindest wenn ich die Großbuchstaben als römische Zahlen interpretiere.

Bau doch mal bitte ein KSKB aus deinem aktuellen stand.
 
ob 'a' vor 'I' kommt darfst du dir überlegen, aber nicht allzu sicher sein,
Groß vs. Kleinbuchstabe macht bei Java nunmal einen Unterschied, es geht quasi nach ASCII-Tabelle
ASCII-Tabelle

mit dem V kann ich dir nun überhaupt nicht mehr folgen,
wenn IIIa vor IIIb kommt, also nach rechts aufsteigend, 'a' und 'b' an 4. Stelle sind klein und werden durchaus sinnvoll verglichen,
dann ist 'V' doch klar größer als 'I', also weiter rechts zu erwarten, warum links?

mit
> VI V IV IIIb IIIa IIb IIa Ib Ia
beschreibst du allerdings wieder eine eher korrekte Ordnung, jedenfalls für die Position der Vs, eben absteigend,

beim von dir in Frage gestellten
> IIIa IIIb IIa IIa IIb IV Ia Ib V VI
ist es offensichtlich erstmal andersum, also V rechts gut aufgeben,

warum IIa nach IIIa steht kann man wiederum fragen, aber das ist wieder Unterschied Groß/ Kleinschreibung
 
KSKB:

Java:
import java.util.Arrays;

class Baumstamm2
implements Comparable<Baumstamm2>
{
	private int nr;
	private double länge;
	private double durchmesser;
	private String klasse;
	private String güteKlasse;
	private double festmeter;

	public Baumstamm2(int nr, double länge, double durchmesser, String klasse, String güteKlasse)
	{
		this.nr = nr;
		this.länge = länge;
		this.durchmesser = durchmesser;
		this.klasse = klasse;
		this.güteKlasse = güteKlasse;
		festmeter =  Math.round(Math.PI/4*durchmesser*länge*100)/100.;
	}

	public String getKlasse()
	{
		return klasse;
	}

	public int compareTo(Baumstamm2 b)
	{
		return this.getKlasse().compareTo(b.getKlasse());
	}

	public String toString()
	{
		return "Baumnummer: " + nr+ "\t Länge: " + länge + "\t Durchmesser: " + durchmesser + "\t Klasse: " + klasse + 
				"\t Güteklasse: " + güteKlasse + "\t Festmeter: " + festmeter;
	}
	
	
}

public class BaumstammTest 
{
	public static void sort(Baumstamm2[] arr) 
	{
		Arrays.sort(arr);
	}
	public static void main(String[] args) 
	{
		Baumstamm2[] arr = new Baumstamm2[10];
		arr[0] = new Baumstamm2(1, 5, 0.25, "Ia", "A");
		arr[1] = new Baumstamm2(2, 5, 0.25, "IIb", "A");
		arr[2] = new Baumstamm2(3, 5, 0.25, "IIa", "A");
		arr[3] = new Baumstamm2(4, 5, 0.25, "Ib", "A");
		arr[4] = new Baumstamm2(5, 5, 0.25, "IV", "A");
		arr[5] = new Baumstamm2(6, 5, 0.25, "IIIa", "A");
		arr[6] = new Baumstamm2(7, 5, 0.25, "IIIb", "A");
		arr[7] = new Baumstamm2(8, 5, 0.25, "V", "A");
		arr[8] = new Baumstamm2(9, 5, 0.25, "VI", "A");
		arr[9] = new Baumstamm2(10, 5, 0.25, "IIa", "A");
		sort(arr);
		
		for(int i = arr.length-1; i>=0; i--)
			System.out.println(arr[i].toString());
		
		
	}

}



Würde es dann helfen, vor dem compareTo() irgendwas mit toLower oder sowas verwenden? (kenne mich da aber nicht aus)
 
Was du offenbar haben willst erhälst du z.B. so:

Java:
public int compareTo(Baumstamm b)
    {
        return this.getKlasse().toUpperCase().compareTo(b.getKlasse().toUpperCase());
    }

Ausgabe:
Ia Ib IIa IIa IIb IIIa IIIb IV V VI
 
> (kenne mich da aber nicht aus)

nicht nur darauf berufen sondern guten Ideen auch selbstbewußt selber folgen!
schau dir die Methoden von String an, es gibt eine die sogar mit toLower.. beginnt,
es gibt auch compareToIgnoreCase() und wer weiß was alles
 

Zurück
Oben