← Blog

Customer Cars und Sortieren 2.0

Das $-Präfix, ein Custom-Comparator — und das Ende einer langen Geschichte mit Bubble Sort

Customer Cars

Bis in die frühen 80er Jahre gab es in der Formel 1 sogenannte "Customer Cars". Einige F1-Teams waren richtiggehende Hersteller von F1-Wagen. Sie bauten die Wagen nicht nur für sich, sondern für jeden zahlenden Kunden — genau wie einige Motorenhersteller. Maserati, Lancia und Ferrari konnten in den 50ern käuflich erworben und eingesetzt werden. In den 60ern waren Cooper, Lotus und Brabham weit verbreitet. In den 70ern kam March als "Massenhersteller" und vereinzelte McLaren und letztlich einige Williams FW07 auf den Markt. Das eine oder andere große Team fing mit solchen "Customer Cars" an — so taten es Tyrrell und Williams, aber auch kleinere Teams wie Hill, RAM und Surtees.

Customer Cars führten dazu, dass die Starterfelder bei einem GP groß waren — zu groß für den Geschmack einiger. Die Eintrittsschwelle für neue Fahrer und Teams war niedrig. Auch waren manche Teams echte "Garagisten" und Träumer — aber gerade diese Underdogs und Träumer haben der Formel 1 einen speziellen Reiz gegeben. Frank Williams war einer der belächelten Garagisten, und hat es mit seinem Team aber mit eisernem Willen zum Weltmeisterteam gebracht. Es gab sogar Teams, die immer zu einem GP (Team Gunston — Südafrika) mit einem Wagen und lokalen Sponsoren und Fahrern antraten. Man musste damals nicht die ganze Saison dabei sein. Entsprechend bunt waren einige Fahrzeuge …

Die Kommerzialisierung/Professionalisierung in den 90ern und das Auftreten großer Hersteller seit den 2000er Jahren bedeuteten das Ende für "Customer Cars" und kleine Teams in der Formel 1 — als auch für die Romantik des ambitionierten Amateurs und seines ehrenwerten Scheiterns. In vielen anderen Motorsportkategorien sind "Customer Cars" nach wie vor Gang und Gäbe, und auch in der Formel 1 wäre dies m.E. möglich und sinnvoll.


In meiner F1-Anwendung müssen die "Werkswagen" und "Customer Cars" aus diversen Gründen unterschieden werden. In der Datenbank ist das eine Sache von Attributen und Werten, bei den Bildern eine Frage der Namenskonvention. Da ich (dem "Pfad" von Sauro Torregianni folgend) relativ spät zu den "Customer Cars" gekommen bin, hatte ich bei der Namenskonvention die Wahl zwischen einem Suffix oder einem Präfix. Ich habe mich für das Präfix $ entschieden — nicht ganz unpassend, wie ich finde.

Ein und derselbe Wagen kann also von zwei oder mehreren Teams eingesetzt werden. Die Customer Cars haben das Präfix $, die "Werkswagen" keinen:

Werkswagen :   1970_Lotus_49C_Ford_Rindt_Monaco_.jpg
Customer Car:  $1970_Lotus_49C_Ford_Charlton_South Africa_.jpg

Die weiteren Felder sind das Jahr, der Konstrukteur, der Motorenhersteller, der Fahrer und das Rennen, jeweils getrennt durch einen _ Underscore. Soweit so gut — nur beim Sortieren der Bilder (und das passiert an einigen Stellen) muss das Präfix ignoriert werden. Das heißt, ein angepasster Algorithmus musste her.

Sortieren

Mein erster Impuls war es, einen eigenen angepassten Sortieralgorithmus zu implementieren. Der "Bubble Sort" und ich haben ja eine lange Geschichte miteinander — aber auf gewisse Weise endet diese hier, denn es besteht keine Notwendigkeit, einen eigenen Algorithmus in JAVA zu entwickeln.

JAVA bietet Sortiermethoden für Arrays und Listen — und diese können sehr smart erweitert und modifiziert werden. Es geht hier um eines der Kernanliegen und -elemente der objektorientierten Programmierung: bestehende Objekte und Methoden können angepasst werden — @Override und Comparator sind die Zauberworte.

Nun aber zum Problem und der Lösung …

Mit der Methode arrayOfFilenames wird der Inhalt des Directories PATH als sortiertes Array von Strings zurückgeliefert:

public static String[] arrayOfFilenames(String PATH) {

    String  pattern  = "_Test_";
    List<String>  fList = new ArrayList<>();
    File    folder   = new File(PATH);
    File[]  files    = folder.listFiles();

    for (File f : files)
        if (!f.getName().contains(pattern) && f.getName().endsWith(".jpg") && f.isFile() && !f.isHidden())
                fList.add(f.getName());

    String[] fileNames = fList.toArray(new String[0]);
    Arrays.sort(fileNames);

    return fileNames;
}

Die Methode Arrays.sort(fileNames); sortiert das Array mit dem Namen fileNames alphabetisch. Sie wird in JAVA bereitgestellt.

Das Comparator Interface

Die Methode gibt es auch mit einem zweiten Argument. Dieses zweite Argument muss ein sogenannter Comparator sein — genauer eine Implementierung des JAVA-Interface Comparator. So ein Comparator ist im Prinzip ein Vergleichsoperator. Der Vergleich zweier "Werte" ist der Kern eines jeden Sortieralgorithmus.

Ein Comparator liefert zu zwei Parametern s1 und s2:

  • eine positive Zahl, wenn s1 vor s2 stehen soll
  • 0, wenn die beiden "gleichwertig" sind
  • eine negative Zahl, wenn s2 vor s1 stehen soll

Es gibt einige vordefinierte Vergleichsoperatoren, die mit Arrays.sort() verwendet werden können. Der gängigste ist Collections.reverseOrder() und er tut mit

Arrays.sort(fileNames, Collections.reverseOrder());

das was man erwarten darf — das Array wird in umgekehrter alphabetischer Reihenfolge sortiert. Das funktioniert mit allen Standard-JAVA-Datentypen.

Nun zum Coden eines eigenen Comparators … Das Comparator-Interface ist im java.util-Package deklariert und definiert eine compare(arg1, arg2)-Methode mit zwei Argumenten, welche die zu vergleichenden Objekte repräsentieren:

public interface Comparator<T> {
    public int compare(T o1, T o2);
}

Ein eigener Comparator MyComparator würde im ersten Schritt das Interface implementieren und die Methode compare überschreiben:

static class MyComparator implements Comparator<String> {
    @Override
    public int compare(String s1, String s2) {
        return s1.compareTo(s2);
    }
}

Die JAVA-String-Methode compareTo() vergleicht zwei Strings lexikografisch (Unicode-Werte). Soweit ist das nichts Neues. Wenn man jetzt bei den zu vergleichenden Strings ein führendes $-Zeichen entfernt, ist die neue Methode fertig!

static class MyComparator implements Comparator<String> {
    @Override
    public int compare(String s1, String s2) {
        String cleanS1 = s1.startsWith("$") ? s1.substring(1) : s1;
        String cleanS2 = s2.startsWith("$") ? s2.substring(1) : s2;
        return cleanS1.compareTo(cleanS2);
    }
}

und mit dem Aufruf

Arrays.sort(fileNames, new MyComparator());
return fileNames;

ist das Problem der führenden $-Zeichen bei "Customer Cars" gelöst.

Comparator mit Collections

Der Vollständigkeit halber — das Interface Comparator ist auch auf Listen bzw. Collections anwendbar; der obige Code kann auch so gestaltet werden:

public static String[] arrayOfFilenames(String PATH) {

    List<String> fList  = new ArrayList<>();
    File         folder = new File(PATH);

    for (File f : folder.listFiles())
        if (!f.getName().contains("_Test_") && f.getName().endsWith(".jpg") && f.isFile() && !f.isHidden())
                fList.add(f.getName());

    Collections.sort(fList, MyComparator);

    return fList.toArray(new String[0]);
}
F1 Photographie ⌂ Blog Photo Archiv (1/3) — Tags
Kommentare (0)