Sortieren kann sehr kompliziert sein. An dieser Stelle erscheint es mir richtig, etwas über Sortieralgorithmen zu erzählen.
Es gibt viele verschiedene Sortieralgorithmen. Grundsätzlich gibt es zwei verschiedene Arten:
Vergleichsbasierte und
nicht-vergleichsbasierte. Bei den vergleichsbasierten werden jeweils zwei Elemente untersucht und bei Bedarf vertauscht. Bei den nicht-vergleichsbasierten besteht zum Beispiel die Möglichkeit die Werte zu zerlegen, in Containern abzulegen und sie mit verschiedenen Gewichtungen neu zusammenzusetzen.
In
diesem Wikipedia-Artikel sind einige Verfahren aufgelistet.
Für den Anfang eignet sich zum Beispiel
Selectionsort. Dabei wird das Array in verschachtelten for-Schleifen durchlaufen. Die äußere Schleife durchläuft alle Elemente, die innere nur alle Elemente, die logisch
nach dem aktuellen der äußeren Schleife stehen.
In der inneren Schleife wird so der kleinste Wert ermittelt und danach mit dem aktuellen Element der äußeren Schleife vertauscht. Damit steht das kleinste Element bereits an erster Stelle, es kann also beim 2. Element mit dem selben Verfahren vorgegangen werden.
Hier findet sich das grafisch dargestellt und beschrieben.
Direkt mit deinem Beispiel arbeiten wäre schwieriger verständlich, daher vorerst an einem simplen Array:
Code:
var numbers = [7, 5, 11, 3, 9];
Jetzt lässt sich die erste Schleife anlegen. Außerdem ist bekannt, dass in jedem Durchlauf das kleinste Element rechts des aktuellen Elementes gefunden werden soll, daher muss eine Variable angelegt werden, die sich den Index dieses Elementes merkt. Anfangs wird davon ausgegangen, dass der aktuelle Index der kleinste ist:
Code:
var numbers = [7, 5, 11, 3, 9];
for(var startIndex = 0; startIndex < numbers.length; startIndex++)
{
var smallestIndex = startIndex;
// Platz für die 2. Schleife
}
Im nächsten Schritt muss die 2. Schleife angelegt werden. Diese beginnt rechts des aktuellen Elementes, also bei
startIndex +1:
Code:
var numbers = [7, 5, 11, 3, 9];
for(var startIndex = 0; startIndex < numbers.length; startIndex++)
{
var smallestIndex = startIndex;
for(var currentIndex = startIndex + 1; currentIndex < numbers.length; currentIndex++)
{
}
}
Als nächstes muss ermittelt werden, ob das aktuelle Element der inneren Schleife kleiner oder für absteigende Sortierung größer als der bisher kleinste bekannte Index ist:
Code:
var numbers = [7, 5, 11, 3, 9];
for(var startIndex = 0; startIndex < numbers.length; startIndex++)
{
var smallestIndex = startIndex;
for(var currentIndex = startIndex + 1; currentIndex < numbers.length; currentIndex++)
{
if(numbers[currentIndex] < numbers[smallestIndex])
{
smallestIndex = currentIndex;
}
}
}
Am Ende eines jeden Durchlaufes der äußeren Schleife muss nun das kleinste bekannte Element mit dem aktuellen vertauscht werden, dafür ist eine temporäre Variable nötig:
Code:
var numbers = [7, 5, 11, 3, 9];
for(var startIndex = 0; startIndex < numbers.length; startIndex++)
{
var smallestIndex = startIndex;
for(var currentIndex = startIndex + 1; currentIndex < numbers.length; currentIndex++)
{
if(numbers[currentIndex] < numbers[smallestIndex])
{
smallestIndex = currentIndex;
}
}
var temp = numbers[startIndex];
numbers[startIndex] = numbers[smallestIndex];
numbers[smallestIndex] = temp;
}
Man könnte noch prüfen ob sich
startIndex überhaupt von
smallestIndex unterscheidet. Wenn nicht, wäre das tauschen sinnlos.
Die Ausgabe des Arrays ergibt nun, dass es erfolgreich sortiert wurde:
Zu deinem Beispiel
Du benutzt nun kein simples Array voller Zahlen, sondern ein multidimensionales, von dem nur ein bestimmter Index des inneren Arrays interessant ist. Außerdem ergibt sich bei dir das Problem, dass du keine Zahlen sondern Strings sortieren möchtest. Auch die reinen Zahlen in deinem Datensatz sind Strings (ich gehe dabei von
deiner Adressverwaltung aus).
Hier kommt es beim Vergleich zu einem kleinen Problem. Strings lassen sich genau so wie Integer (Zahlen) mit den Vergleichsoperatoren
> und
< vergleichen:
Code:
var compare = "A" < "B"; // true
var compare = "Giraffe" < "Affe"; // false
Bei Zahlen, die als String gespeichert sind, kommt es jedoch zu merkwürdigem Verhalten:
Code:
var compare = "7" < "15"; // false
Hier muss also mittels der
parseInt-Funktion der String in einen Integer umgewandelt werden, um korrekte Ergebnisse zu erzielen.
Darum muss bei dem Vergleich deiner Daten jedes mal zusätzlich geprüft werden, ob es sich um Integer handelt oder nicht.
Aufrufen kannst du die Funktion ganz einfach durch deine
th-Elemente im HTML Code. Eventlistener wären die saubere Lösung, jedoch hast du bisher ohne gearbeitet, daher mache ich das genau so wie du:
HTML:
<tr>
<th onclick="sort(0)">Name</th>
<th onclick="sort(1)">Vorname</th>
<th onclick="sort(2)">Straße</th>
<th onclick="sort(3)">Hausnummer</th>
<th onclick="sort(4)">PLZ</th>
<th onclick="sort(5)">Ort</th>
<th onclick="sort(6)">E-Mail</th>
<th onclick="sort(7)">Webadresse</th>
<th colspan="2">Aktion</th>
</tr>
Die Zahl repräsentiert dabei den Index des betreffenden Elementes in deinem Array. Die Funktion dazu würde so aussehen:
Code:
function sort(thIndex)
{
for(var startIndex = 0; startIndex < datensatz.length; startIndex++)
{
var smallestIndex = startIndex;
for(var currentIndex = startIndex + 1; currentIndex < datensatz.length; currentIndex++)
{
if(datensatz[currentIndex][thIndex].toUpperCase() < datensatz[smallestIndex][thIndex].toUpperCase())
{
smallestIndex = currentIndex;
}
}
var temp = datensatz[startIndex];
datensatz[startIndex] = datensatz[smallestIndex];
datensatz[smallestIndex] = temp;
}
}
thIndex ist die aus dem Funktionsaufruf übergebene Zahl. Damit wird beim Vergleich einfach das entsprechende Element (zum Beispiel bei 0 auf die Vornamen) verwendet.
Damit lassen sich die Strings (Name, Vorname, Straße, Ort, E-Mail, Webadresse) bereits aufsteigend sortieren (und zwar mit einem Klick auf die entsprechende Spaltenüberschrift).
Das Problem mit den Integern lässt sich recht leicht beheben. Es wird einfach zu Beginn geprüft, ob in der entsprechenden Spalte Integer verwendet werden oder eben nicht. Dein möglicher Adresszusatz macht die Sache etwas schwieriger. Hausnummern fangen aber meines Wissens nach trotzdem mit einer Zahl an, daher reicht es, das erste Zeichen zu vergleichen.
An sich wird nur die durch
parseInt konvertierte Variable mit der unkonvertierten geprüft und dementsprechend eine Variable
true oder
false gesetzt:
Code:
if(parseInt(datensatz[0][thIndex].substr(0, 1)) == datensatz[0][thIndex].substr(0, 1))
{
var integer = true;
}
else
{
var integer = false;
}
// Oder die kürzere Fassung mit dem ternären Operator:
var integer = (parseInt(datensatz[0][thIndex].substr(0, 1)) == datensatz[0][thIndex].substr(0, 1)) ? true : false;
In der inneren Schleife muss jetzt abgefragt werden, ob es sich um Integer handelt oder nicht und dementsprechend müssen geparste oder ungeparste Werte verglichen werden:
Code:
var integer = (parseInt(datensatz[0][thIndex].substr(0, 1)) == datensatz[0][thIndex].substr(0, 1)) ? true : false;
for(var startIndex = 0; startIndex < datensatz.length; startIndex++)
{
var smallestIndex = startIndex;
for(var currentIndex = startIndex + 1; currentIndex < datensatz.length; currentIndex++)
{
if(integer)
{
if(parseInt(datensatz[currentIndex][thIndex]) < parseInt(datensatz[smallestIndex][thIndex]))
{
smallestIndex = currentIndex;
}
}
else
{
if(datensatz[currentIndex][thIndex].toUpperCase() < datensatz[smallestIndex][thIndex].toUpperCase())
{
smallestIndex = currentIndex;
}
}
}
var temp = datensatz[startIndex];
datensatz[startIndex] = datensatz[smallestIndex];
datensatz[smallestIndex] = temp;
}
Jetzt könnte man noch einfügen, dass bei einem erneuten Klick auf eine Spaltenüberschrift die Sortierung von aufsteigend zu absteigend wechselt. Außerdem müssen gleiche Zahlen mit unterschiedlichen Zusätzen wie Strings behandelt werden (z. B.
15a und
15b. Das lasse ich zum herumtesten mal mit einem unkommentierten Beispiel stehen:
Code:
var sortIndex = -1;
var asc = true;
function sort(thIndex)
{
if(thIndex != sortIndex)
{
sortIndex = thIndex;
asc = true;
}
else
{
asc = (!asc) ? true : false;
}
var integer = (parseInt(datensatz[0][thIndex].substr(0, 1)) == datensatz[0][thIndex].substr(0, 1)) ? true : false;
for(var startIndex = 0; startIndex < datensatz.length; startIndex++)
{
var smallestIndex = startIndex;
for(var currentIndex = startIndex + 1; currentIndex < datensatz.length; currentIndex++)
{
if(integer)
{
if
(
(asc && parseInt(datensatz[currentIndex][thIndex]) < parseInt(datensatz[smallestIndex][thIndex])) ||
(!asc && parseInt(datensatz[currentIndex][thIndex]) > parseInt(datensatz[smallestIndex][thIndex]))
)
{
smallestIndex = currentIndex;
}
else if(parseInt(datensatz[currentIndex][thIndex]) == parseInt(datensatz[smallestIndex][thIndex]))
{
if
(
(asc && datensatz[currentIndex][thIndex].toUpperCase() < datensatz[smallestIndex][thIndex].toUpperCase()) ||
(!asc && datensatz[currentIndex][thIndex].toUpperCase() > datensatz[smallestIndex][thIndex].toUpperCase())
)
{
smallestIndex = currentIndex;
}
}
}
else
{
if
(
(asc && datensatz[currentIndex][thIndex].toUpperCase() < datensatz[smallestIndex][thIndex].toUpperCase()) ||
(!asc && datensatz[currentIndex][thIndex].toUpperCase() > datensatz[smallestIndex][thIndex].toUpperCase())
)
{
smallestIndex = currentIndex;
}
}
}
var temp = datensatz[startIndex];
datensatz[startIndex] = datensatz[smallestIndex];
datensatz[smallestIndex] = temp;
}
tabneuzeichnen(); // Funktion von Beavis1311
}
Schleifen debuggen kann sehr nervig sein. Wenn du Fragen hast oder auf Probleme stößt lass es uns einfach wissen, wir können dir sicher helfen.
Bitte auch Bescheid geben, falls ich einen Fehler eingebaut habe.