[Java] Objekte in einer ArrayList sortieren

Ich habe die Klasse Arten:

Code:
package mampf;

public class Arten {
    private String art;
    
    public Arten(String art){
        this.art = art;
    }
    
    public Arten(){
        this.art = null;
    }
    
    public String getArt(){
        return this.art;
    }
    
    public void setArt(String art){
        this.art = art;
    }
}

Daraus wurden Objekte erzeugt, die auch als solche in einer Objekt-Datenbank (db4o) gespeichert wurden.

Wenn ich die Objekte dieses Typs aus der Datenbank lese, werden sie in eine ArrayList geschrieben.
Dumm ist nur, dass sie in die ArrayList in der Reihenfolge eingefügt werden, in der sie auch in der Datenbank gespeichert wurden. Daher möchte ich diese Objekte alphabetisch sortieren, und zwar nach der Eigenschaft art.

Nun habe ich gelesen, dass man so etwas mit Collections und Comparatoren realisieren kann. Problem ist aber, dass die Beispiele, die ich finde, relativ simpel sind, d.h., es gibt zwei Strings oder Integer-Werte im Array, und dazu wird ein Comparator erstellt und dann per Collections.sort() sortiert. Bei mir wird aber nicht nach dem Eintrag in der ArrayList sortiert, sondern nach einer Eigenschaft aus dem Eintrag (der Eintrag ist in dem Falle ein Objekt der Klasse Arten).
So wie ich das sehe, hat Comparator nur zwei Parameter für die Strukturen, die es vergleichen soll. Ich brauche aber mehr, da ich mehr als nur zwei Einträge in der ArrayList habe.

Mich beschleicht eh das Gefühl, dass ich da etwas falsch verstanden habe, weil ich mir nicht vorstellen kann, wie das so klappen soll. Vielleicht gibt es aber auch eine andere Möglichkeit so etwas zu bewerkstelligen.

Im Prinzip ist die Situation folgende:
Ich hab einige Objekte einer bestimmten Klasse, und möchte diese Objekte alphabetisch oder numerisch (je nach Anforderung) nach einer bestimmten Eigenschaft der Objekte sortieren.
Dabei sollte man bedenken, dass ich auch Klassen haben werde, die etwas komplexer aufgebaut sein werden, als diese hier (Arten). Es wird mehr Eigenschaften geben, nach denen ich sortieren möchte.
Es kann auch mal der Fall auftreten, dass ich Objekte habe, die als erstes Sortiermerkmal ein Datum und als zweites einen String haben.
Wie macht man so etwas in Java?
 
Du hast im Grunde 2 Möglichkeiten: Entweder du schreibst einen Comparator, der erhält dann zwei deiner Arten-Objekte und gibt dann zurück welches größer ist(je nachdem ob das int, was er zurückgibt positiv oder negativ oder null ist. Du musst dafür nicht alle deiner Objekte übergeben bekommen, den Rest erledigt ja der Sortieralgorithmus für dich.

Die zweite Möglichkeit ist, dass du in deiner Klasse das Interface Comparable implementierst und dann eine Methode schreibst, die in etwa so aussieht:

Code:
public int compareTo(Arten a1)
{
   return this.getArt().compareTo(a1.getArt());
}
(Hierbei nutzt man aus, dass String bereits Comparable implementiert.)

Danach brauchst du eigentlich nur noch Collections.sort() aufzurufen.

Es kann auch mal der Fall auftreten, dass ich Objekte habe, die als erstes Sortiermerkmal ein Datum und als zweites einen String haben.
Wie macht man so etwas in Java?

Also ich würde das so machen(1. Kriterium art, 2. Kriterium foo):
Code:
public int compareTo(Arten a1)
{
   int result = this.getArt().compareTo(a1.getArt());
   if(result != 0)
      return result;
   else {
       return this.getFoo().compareTo(a1.getFoo());
       /*vorausgesetzt, getFoo liefert ein Objekt zurück, was Comparable implementiert */
   }
}
 
Ich mach das immer so:

Code:
import java.util.Collections;

Code:
Collections.sort(MyArrayList, new Comparator(){
	public int compare(Object arg0, Object arg1) {
	        return ((MyObject)arg0).getId().compareTo(((MyObject)arg1).getId());
	}
});
 
Original von Lesco
Du musst dafür nicht alle deiner Objekte übergeben bekommen, den Rest erledigt ja der Sortieralgorithmus für dich.

Diesen Satz im Zusammenhang mit deinem Beispiel verstehe ich nicht.
compare heißt doch vergleichen. Wenn ich zwei Objekte aus einer Menge von vielen miteinander vergleiche, habe ich doch nur die Reihenfolge innerhalb der beiden Objekte und nicht innerhalb der gesamten Menge an Objekten, oder nicht?
 
Original von GambaJo
compare heißt doch vergleichen. Wenn ich zwei Objekte aus einer Menge von vielen miteinander vergleiche, habe ich doch nur die Reihenfolge innerhalb der beiden Objekte und nicht innerhalb der gesamten Menge an Objekten, oder nicht?
Hm, der Algoritmus soll ja anhand dieser Information die ganze Liste ordnen - nach dieser Eigenschaft. Mathematisch gesehen sollte sowas transitivität heißen:
man weiß dass X<Y und Y<Z , daraus folgt, dass X<Z
Das heißt, um eine Liste mit Zahlen zu sortieren, braucht man immer nur 2 Zahlen gleichzeitig miteinander zu verlgeichen.

Falls Du nur ein größeres Beispiel suchst:
sortiert Funktionen und Variablendeklarationen in einem Baum:
Code:
Comparator <PDeclaration> comp=new Comparator<PDeclaration>()
	{
		public int compare(PDeclaration decl1,PDeclaration decl2)
		{
			if ((decl1 instanceof AVarDeclaration)
					&&(decl2 instanceof AVarDeclaration)) return 0;
			//var decl als 1 Argument= immer kleiner
			if (decl1 instanceof AVarDeclaration) return -1;
			//als zweites => immer größer (da der Fall Var,Var abgedeckt ist
			if (decl2 instanceof AVarDeclaration) return 1;
            //platziere Maindecl direkt nach Variablen
			if ((decl1 instanceof AMainDeclaration)
					&&(decl2 instanceof AFuncDeclaration)) return -1;
			if ((decl1 instanceof AFuncDeclaration)
					&&(decl2 instanceof AMainDeclaration)) return 1;
			return 0;
			
			
		}
	};
	//sortiere die declarationen, damit später die Variablen in einem Block stehen:
	 public void inAWhereBlock(AWhereBlock node)
	    {
	      Collections.sort(node.getWhereBody(),comp);
	    }
Das Prinzip: man soll bei 2 Objekten immer eindeutig sagen können, welches "größer"/"kleiner" ist oder ob die beiden gleich sind.
Man gibt also 1 zurück, falls Parameter 1 "größer" ist als Parameter 2,
0 - falls beide gleich sind und -1 falls Param1 <Param2.
Wie man an diese Infos kommt, interessiert "niemanden". Bei gewöhnlichen Datentypen kann man die "buildIn" compareTo - Methoden nutzen oder wie im Beispiel oben eine Fallunterscheidung machen.
Hauptsache (und das ist auch in der Java-Doc vermerkt) es gilt die transitivität:
also wenn obj1<obj2 und obj2 < obj10, dann ist obj1 automatisch < obj10

Bsp (so wie ich Dein Problem verstehe):
Code:
Comparator <MyObject> comp=new Comparator<MyObject>()
	{
		public int compare(MyObject obj1,MyObject obj2)
		{   
			//super sonderfall - wenn obj1 GambaJo heißt, ist es immer größer!
			if (obj1.getName==GambaJo) return 1 ;    
                      //wenn beide gleich sind,vergleiche Strings:
			if (obj1.getDate().compareTo(obj2.getDate()==0)
                               return obj1.getString().compareTo(obj2.getString());

			else return obj1.getDate().compareTo(obj2.getDate());
		}
	};
 
Ah, ich glaube, ich fange an zu verstehen.
die Methode compareTo oder der Comparator sind Methoden/Objekte, die Collections erwartet. Ist diese Methode vorhanden bzw. wird dieses Objekt übergeben, weiß Collections selbst, was es zu tun hat, wenn man sort() aufruft.

Mein Fehler lag darin, dass ich dachte, man müsse das manuell machen.

EDIT:

Klasse nun so aufgebaut:

Code:
public class Arten implements Comparable<Arten> {
    private String art;
    
    public Arten(String art){
        this.art = art;
    }
    
    public Arten(){
        this.art = null;
    }
    
    public String getArt(){
        return this.art;
    }
    
    public void setArt(String art){
        this.art = art;
    }
    
    public int compareTo(Arten art)
    {
       int result = this.getArt().compareTo(art.getArt());
       return result;
    }
}

Damit funktioniert es.
Hat man Klassen mit mehr Eigenschaften, macht es sicher keinen Sinn eine feste compareTo() Methode einzufügen, sondern nach Bedarf einen Comparator zu nutzen, weil die ja flexibler sind.

Danke allen Beteiligten.
 
Zurück
Oben