Comparator - Sortierkriterium

magic_halli

Erfahrenes Mitglied
Hallo,

ich möchte Zeichenketten aufsteigend sortieren lassen. Alle (fast) Zeichenketten bestehen aus Zahlen und Trennstrichen, gefolgt von '__' und danach ein Name, z.B.
123456__name
123456-1__name
123456-1-1__name
123456-11-1__name
123456-2-1__name
123456-2-2__name
123456-2-1-1__name
123456-20__name
123456-20-1__name
usw.
Hierzu habe ich einen Comparator geschrieben, der diese Zeichenketten nur nach der Zahlenkombination bis zum '__' sortiert:
Code:
Comparator comparator = new Comparator() {
        public int compare(Object arg0, Object arg1) {
           String name1 = (String) arg0;
           String name2 = (String) arg1;
           
           String str1 = name1.substring(0,name1.lastIndexOf("__"));
           String str2 = name2.substring(0,name2.lastIndexOf("__"));

           return str1.compareTo(str2);
        }
     };
Das geht auch soweit erstmal.
Nur sortiert mir der Comparator diese Zeichenketten eben nach Stringsortierungs-Kriterium und nicht nach Integer-Kriterium, d.h. nach einer 1 kommt eine 11 und keine 2, also:
123456-1
123456-11
123456-2
123456-21
123456-3
usw.

Korrekterweiße sollte es aber so aussehen:
123456-1
123456-2
123456-3
123456-11
123456-21
usw.

Läßt sich das irgendwie bewerkstelligen, dass ich die Zeichenkette quasi nummerisch aufsteigend sortieren kann?

Danke.
 
Du brauchst führenden Nullen, müsstest also eine -1 in -01 bzw. 001 umwandeln.

Auf "-" und "_" parsen, die Länge dazwischen bestimmen und 'fehlende' Felder führend mit Nullen auffüllen.
 
Ok, den entsprechenden Teil in int umwandeln oder statt '-' eine 0 einsetzen is ja kein Ding.
Aber alle Strings kommen ja erstmal aus einer ArrayList... dann wandel ich den zu vergleichenden Teil in int um und dann...?
Ich will ja am Schluß meine ArrayList sortiert vorliegen haben, um mit jedem Eintrag der Reihe nach (da ja dann sortiert) etwas zu machen!

Deshalb habe ich ja meinen separaten Comparator, den ich in einer anderen Funktion aufrufe und die ArrayList (matchesPDF) übergebe, die dann sortiert werden soll.
Code:
Collections.sort(matchesPDF, comparator);

Mir ist nicht ganz klar, wie ich meine int-Werte in sortierter Reihenfolge in die ArrayList bringe bzw. wie ich im Comparator letztendlich 'return str1.compareTo(str2);' anwenden kann?!
 
Anmerkung: in meinem letzten Post habe ich Mist geschrieben - bitte als hinfällig betrachten, Danke :-(

Ich habe jetzt folgendes ausprobiert:
Code:
Comparator comparator = new Comparator() { // eigene Vergleichsoperation!
        public int compare(Object arg0, Object arg1) {
           String name1 = (String) arg0;
           String name2 = (String) arg1;
           
           String str1 = name1.substring(0,name1.lastIndexOf("__"));
           String str2 = name2.substring(0,name2.lastIndexOf("__"));

           String[] werte1 = str1.split("-");
           String[] werte2 = str2.split("-");


           int i = 0;
           while((i<werte1.length)&&(i<werte2.length)) {
        	 int value1 = Integer.parseInt(werte1[i]);
             int value2 = Integer.parseInt(werte2[i]);

             if(value1>value2) {
            	 return 1;
             } else if(value1<value2) {
            	 return -1;
             }
           }

           if(werte1.length>werte2.length) {
        	   return 1;
           } else if (werte1.length<werte2.length) {
        	   return -1;
           } else {
             return 0;
           }

        }
     };
Doch irgendwie scheint hier ein Fehler zu sein, da in der Funktion, welche den Komparator aufruft und dann mit der sortierten ArrayList etwas macht, die Abarbeitung hängen bleibt.

Würde die Sortierung so prinzipiell erstmal funktionieren?
 
Code:
           int i = 0;
           while((i<werte1.length)&&(i<werte2.length)) {
        	 int value1 = Integer.parseInt(werte1[i]);
             int value2 = Integer.parseInt(werte2[i]);

             if(value1>value2) {
            	 return 1;
             } else if(value1<value2) {
            	 return -1;
             }
           }

Deine Schleife terminiert nicht, denn i ist statisch 0.
 
:confused:
Ich bekomme das einfach nicht gebacken... habe mittlerweile tausend Sachen ausprobiert, aber nichts geht so richtig! Habe nun auch noch eine (naive) Variante versucht...

Ich hole mir erstmal den Teil vorm '__' aus meinen Strings:
Code:
String str1 = name1.substring(0,name1.lastIndexOf("__"));
String str2 = name2.substring(0,name2.lastIndexOf("__"));
Dann ersetze ich die '-' durch 0:
Code:
str1 = str1.replaceAll("-", "0");
str2 = str2.replaceAll("-", "0");
Dann parse ich die Strings zu int und will einfach mal ganz naiv diese beiden Werte vergleichen und entsprechend meine return-Werte setzen:
Code:
Comparator comparator = new Comparator() {
     public int compare(Object arg0, Object arg1) {
...
           while((str1.length()>0) && (str2.length()>0)){
               int w1 = Integer.parseInt(str1);
               int w2 = Integer.parseInt(str2);
               
               if(w1>w2){
            	   return 1;
               }else if(w1<w2){
            	   return -1;
               }else{
            	   return 0;
               }
           }
     }
}
Wieso geht das nicht? Ich bekomme die Fehlermeldung: "This method must return a result of type int". Ich bin echt ratlos.

@Navy
Auf "-" und "_" parsen, die Länge dazwischen bestimmen und 'fehlende' Felder führend mit Nullen auffüllen.
So richtig versteh ich das leider nicht, wie das gehen soll bzw. wie ich hierauf meinen Vergleich machen soll.
 
Code:
String str1 = name1.substring(0,name1.lastIndexOf("__"));
String str2 = name2.substring(0,name2.lastIndexOf("__"));
> Dann ersetze ich die '-' durch 0:

Nein, denn dann hast Du genau garnichts erreicht. Du mußt das Format Deiner Namen auf : "$NUMMER-"+n*"$ZAHL" bringen, also die letzte Zahl auf ein n-stelliges Format wandeln (mit n= Länge des größten Wertes). Bei Dir würde es dann so aussehen:

123456-01
123456-11
123456-02
123456-21
123456-03

(n = 2)

Code:
str1 = str1.replaceAll("-", "0");
str2 = str2.replaceAll("-", "0");
> Dann parse ich die Strings zu int und will einfach mal ganz naiv diese beiden Werte
> vergleichen und entsprechend meine return-Werte setzen:
Code:
Comparator comparator = new Comparator() {
     public int compare(Object arg0, Object arg1) {
...
           while((str1.length()>0) && (str2.length()>0)){
               int w1 = Integer.parseInt(str1);
               int w2 = Integer.parseInt(str2);
               
               if(w1>w2){
            	   return 1;
               }else if(w1<w2){
            	   return -1;
               }else{
            	   return 0;
               }
           }
     }
}
> Wieso geht das nicht? Ich bekomme die Fehlermeldung: "This method must return a
> result of type int". Ich bin echt ratlos.

steht doch da. Überleg mal was passiert, wenn str1.length()= 0 oder str2.length = 0 ist. Hint: Du *mußt* einen Wert übergeben.

> So richtig versteh ich das leider nicht, wie das gehen soll bzw. wie ich hierauf meinen
> Vergleich machen soll.

Ich möchte Dir hier keine Lösung anfertigen, nur eben auf die Sprünge helfen. In Deinem vorherigen Beispiel hast Du eine Schleife solange durchlaufen lassen, wie i < $WERT ist, nur verändert sich i nicht und damit läuft die Schleife endlos. Also entweder passt Du Deine Abbruchbedingung an, oder Du veränderst i *in* der Schleife.
 
Ich weiss nicht ob die Reihenfolge ganz die gewünschte ist, aber so gehts auf jeden Fall:
Java:
package de.tutorials;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

/**
 * @author zeja
 */
public class Sorter {

	public static void main(String[] args) {
		ArrayList<String> data = new ArrayList<String>( );
		data.add("123456__name");
		data.add("123456-1__name");
		data.add("123456-2-1__name");
		data.add("123456-2-2__name");
		data.add("123456-2-1-1__name");
		data.add("123456-1-1__name");
		data.add("123456-11-1__name");
		data.add("123456-20__name");
		data.add("123456-20-1__name");

		Collections.sort(data, new Comparator<String>( ) {

			/*
			 * (non-Javadoc)
			 * 
			 * @see java.util.Comparator#compare(java.lang.Object,
			 *      java.lang.Object)
			 */
			public int compare(String strg, String other) {
				String str1 = strg.substring(0, strg.lastIndexOf("__"));
				String str2 = other.substring(0, other.lastIndexOf("__"));

				str1 = str1.replaceAll("-", "0");
				str2 = str2.replaceAll("-", "0");

				for (int i = 0; i < str1.length( ) && i < str2.length( ); i++) {
					try {
						int one = Integer.parseInt(str1.charAt(i) + "");
						int two = Integer.parseInt(str2.charAt(i) + "");

						if (one > two) {
							return 1;
						}
						else if (one < two) {
							return -1;
						}
					}
					catch (NumberFormatException e) {

					}
				}
				return 0;
			}
		});

		System.out.println(data);
	}
}
 
@Navy:
Ok, ich benutze wieder den Code von weiter oben mit 'i' in der while-Schleife. i zähle ich in der Schleife hoch:
Code:
int i = 0;
while((i<werte1.length)&&(i<werte2.length)) {
        int value1 = Integer.parseInt(werte1[i]);
        int value2 = Integer.parseInt(werte2[i]);
        i++;
...}
Allerdings sind in meinen Ausgangsstring nicht nur welche mit nur einem '-', sondern es können eigentlich beliebig viele '-' vorkommen, z.B.
123465-1-1-1
123465-1-1-2
123465-2-1-2-1 usw.
Macht das für Deine Erklärung einen Unterschied oder ist das egal?

@Zeja:
Ja, das funktioniert, aber die Reihenfolge ist irgendwie durcheinander?! Trotzdem Danke.
 
Zuletzt bearbeitet:
Zurück