Comparator - Sortierkriterium

Status
Nicht offen für weitere Antworten.

magic_halli

Bekanntes 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.
 
Hi,

das einfachste wird sein, wenn du deine Zeichenkette zahl1-zahl2 in die erste Zahl und und zweite Zahl zerlegst. Dann die beiden vorderen Zahlen vergleichst und bei Gleichheit die hintere Zahl vergleichst. Achso um einen numerischen Vergleich zu erreichen solltest du die Zeichenketten in Zahlen konvertieren.

Code:
public int compare(Object arg0, Object arg1) {
  String name1 = (String)arg0;
  String name2 = (String)arg1;

  int name1_first = Integer.parseInt(name1.substring(0,name1.lastIndex("-")));
  int name1_seconde = Integer.parseInt(name1.substring(name1.lastIndex("-")+1,name1.lastIndex("__")));

  int name2_first = Integer.parseInt(name2.substring(0,name2.lastIndex("-")));
  int name2_seconde = Integer.parseInt(name2.substring(name2.lastIndex("-")+1,name2.lastIndex("__")));

  if(name1_first==name2_first) {
    if(name1_second>name2_second) {
      return 1;
    } else if(name1_second<name2_second) {
      return -1;
    } else {
      return 0;
    }
  } else {
    if(name1_first>name2_first) {
      return 1;
    } else if(name1_first<name2_first) {
      return -1;
    } else {
      return 0;
    }
  }
}

hab das ganze jetzt nicht getestet, sollte aber das Prinzip mehr als verdeutlichen.

Martin
 
Danke erstmal... das könnte klappen :wink:
Nur kann/wird es eben auch vorkommen, das ich nicht nur Zahl1 und Zahl2 habe sondern auch noch Zahl3, Zahl4 usw.
Das kann ich leider nicht vorhersehen, da diese ganzen Zeichenketten aus einer ArrayList kommen und eben auch nicht festgelegt ist, wieviel Zahlx noch hinten dran hängen! :cry:
 
Hi,

magic_halli hat gesagt.:
Nur kann/wird es eben auch vorkommen, das ich nicht nur Zahl1 und Zahl2 habe sondern auch noch Zahl3, Zahl4 usw.
Das kann ich leider nicht vorhersehen, da diese ganzen Zeichenketten aus einer ArrayList kommen und eben auch nicht festgelegt ist, wieviel Zahlx noch hinten dran hängen! :cry:

ok, das macht die Sache ein wenig komplizierter.

Am besten du trennst zuerst den Teil nach den unterstrichen ab. Danach splittest du deine Zeichenkette an den Bindestrichen. Damit erhälst du ein Array von Strings. Diese beiden Arrays werden dann miteinander verglichen.

Ausformuliert könnte das so aussehen, ist aber nicht getestet.

Code:
compareTo(Object arg0, Object arg1) {

  String name1 = (String)arg0;
  String name2 = (String)arg1;

  name1 = name1.subString(0,name1.lastIndex("__");
  name2 = name2.subString(0,name2.lastIndex("__");

  String[] werte1 = name1.split("-");
  String[] werte2 = name2.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;
  }
}

ich bin jetzt davon ausgegangen, dass die längere Zeichenkette die größere ist, wenn sie sonst übereinstimmen.


Martin
 
Cool, das leuchtet mir erstmal ein :toll:

Nur weiß ich aber leider nicht, wie ich im Comparator mein 'return str1.compareTo(str2);' auf String[] anwenden soll ... denn String[] geht nicht mit compareTo!
In einer anderen Funktion benutze ich diesen Comparator wieder, indem ich ihn wie folgt aufrufe:
Code:
//sortiert die ArrayList matchesPDF mittels Comparator-Interface
Collections.sort(matchesPDF, comparator);
 
Betr.: mein letzter Post...

Sorry, ich habe in meinem letzten Post Mist geschrieben!!! :roll: Bitte als hinfällig betrachten - Danke.

@merxleben
Wenn ich den Code so übernehme, hat das den Effekt, das eigentlich gar nicht sortiert wird, obwohl die return-Werte richtig gesetzt sind! ...das versteh ich nicht!?
Kann der Fehler vielleicht irgendwie bei dem int i=0 liegen, da ja das i quasi immer statisch auf 0 steht?
 
Hi,

wie gesagt ich hab den Code so aus dem Bauch ohne testen hingeschrieben. Ich werds heute abend vielleicht mal ausprobieren.

Die Zuweisung zu int i=0 ist nur für die Schleife wesentlich. Hat also für das Ergebnis keine weitere Bedeutung

Martin
 
Hi,

ich hab das ganze mal getestet. In meinem Code hatte ich nur eine wesentliche Kleinigkeit vergessen. Man sollte eine Zählervariable auch hochzählen, sonst kann sie ihren Zweck auch nicht erfüllen.

Das ganze Beispiel am Stück

Code:
import java.util.Arrays;
import java.util.Comparator;

public class Vergleich {

	public static void main(String[] args) {
		
		Comparator comp = new Comparator() {
			public int compare(Object arg0, Object arg1) {
				String name1 = (String)arg0;
				String name2 = (String)arg1;
				
				name1 = name1.substring(0,name1.lastIndexOf("__"));
				name2 = name2.substring(0,name2.lastIndexOf("__"));
				
				String[] werte1 = name1.split("-");
				String[] werte2 = name2.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;
					}
					i++;
				}
				
				if(werte1.length>werte2.length) {
					return 1;
				} else if(werte1.length<werte2.length) {
					return -1;
				} else {
					return 0;
				}				
			}
		};
		
		String[] feld = new String[5];
		feld[0] = "1-3-55-6__34";
		feld[1] = "1-3-55__33";
		feld[2] = "3-4__45";
		feld[3] = "7__5";
		feld[4] = "3-1__5";
		
		Arrays.sort(feld,comp);
		
		for(int i=0;i<feld.length;i++) {
			System.out.println("Pos: "+i+" Wert: "+feld[i]);
		}				
	}

}

Martin
 
Absolut... ich hatte zwar i auch hochgezählt - nur leider an der verkehrten Stelle :roll:

Endlich, nach einer schweißgebadeten schlaflosen Nacht geht die Sache - tausend Dank an Dich 😀

Danke und Gruß.
 
Hallo,

folgende Frage:

Wie kann Ich es bewerkstelligen, dass Ich mit der compareTo-Methode wählen kann, welche Attribute miteinander verglichen werden sollen, d.h. so eine Art "globaler" Schalter.

Irgendwas mit enumeration?
 
anderenfalls sollte JEDES Objekt ein Schalter-Objekt kennen, das es nach der aktuellen Schaltung fragen kann,
recht aufwendig, weniger aufwendig und noch unsauberer wirds mit einem statischen Schalter,

in jedem Fall total unsauber,
lieber Comparator, ein externes Objekt, das die Sortierung in die Hand nimmt
 
Status
Nicht offen für weitere Antworten.

Zurück
Oben