SORTBY.KEYRANGE(Array;Keys;Header) mit
Array: Zu sortierender Bereich
Keys: Erste Zelle eines 2x9-Bereichs für bis zu 9 Sortierschlüssel (oben: Feldnr.; unten: Sortierrichtung 0 auf, 1 ab)
Header: 1 bedeutet "enthält Feldnamen", 0 oder leer bedeutet "enthält keine Feldnamen".
Motivation zu der Funktion:
4 Mängel von SORTIERENNACH()
Ausstattung von SORTBY.KEYRANGE
Daher steuere ich die 18 Sortierparameter einzeln zugewiesen in die LET-(bzw. SORTIERENNACH)-Funktion; das bedeutet 1 bis 9 Sortierungen auf einen Schlag, die wohl noch niemand benötigt hat (falls doch: Funktion einfach schachteln). Das Feld "Keys" verwaltet dies in 2 Zeilen x 9 Spalten, die leer bleiben müssen, wenn sie nicht alle benötigt werden.
Bereich "Keys"
Oberste Sortierung: Getränk [1] wird aufsteigend [leer] sortiert
dahinter: Farbe [2] wird absteigend [1] sortiert
dahinter: Herkunft [4] wird aufsteigend [1] sortiert
dahinter: Geschmack [3] wird absteigend [leer] sortiert (wie man sieht, greift dieser Untersort im Beispiel sogar noch)
Lambda-Funktion
=LAMBDA(Array;Keys;Header;LET(
a;Array;
p;Keys;
t;Header;
offs;BEREICH.VERSCHIEBEN(p;;;2;9);
h;WENN(SEQUENZ(2)=2;1-offs*2;offs);
L;SEQUENZ(ZEILEN(a));
m;SEQUENZ(ZEILEN(a)-t;;1+t);
n;SEQUENZ(;SPALTEN(a));
o;SEQUENZ(;SPALTEN(h));
j;INDEX(h;1;o);
k;INDEX(h;2;o);
s;SORTIERENNACH(INDEX(a;m;n);
INDEX(a;m;WENNFEHLER(1/(1/INDEX(j;1));INDEX(j;1)));WENN(ISTFEHLER(INDEX(j;1));INDEX(k;1);INDEX(k;1));
INDEX(a;m;WENNFEHLER(1/(1/INDEX(j;2));INDEX(j;1)));WENN(ISTFEHLER(INDEX(j;2));INDEX(k;1);INDEX(k;2));
INDEX(a;m;WENNFEHLER(1/(1/INDEX(j;3));INDEX(j;1)));WENN(ISTFEHLER(INDEX(j;3));INDEX(k;1);INDEX(k;3));
INDEX(a;m;WENNFEHLER(1/(1/INDEX(j;4));INDEX(j;1)));WENN(ISTFEHLER(INDEX(j;4));INDEX(k;1);INDEX(k;4));
INDEX(a;m;WENNFEHLER(1/(1/INDEX(j;5));INDEX(j;1)));WENN(ISTFEHLER(INDEX(j;5));INDEX(k;1);INDEX(k;5));
INDEX(a;m;WENNFEHLER(1/(1/INDEX(j;6));INDEX(j;1)));WENN(ISTFEHLER(INDEX(j;6));INDEX(k;1);INDEX(k;6));
INDEX(a;m;WENNFEHLER(1/(1/INDEX(j;7));INDEX(j;1)));WENN(ISTFEHLER(INDEX(j;7));INDEX(k;1);INDEX(k;7));
INDEX(a;m;WENNFEHLER(1/(1/INDEX(j;8));INDEX(j;1)));WENN(ISTFEHLER(INDEX(j;8));INDEX(k;1);INDEX(k;8));
INDEX(a;m;WENNFEHLER(1/(1/INDEX(j;9));INDEX(j;1)));WENN(ISTFEHLER(INDEX(j;9));INDEX(k;1);INDEX(k;9)));
u;WENN(t;WENN(L=1;INDEX(a;1;n);INDEX(s;L-1;n));s);
u))
Das u am Schluss definiere ich zunächst, um es dann einzeln als Funktions-Rückgabe nochmals zu schreiben. Vorteil: Man kann alle Zwischenschritte der Funktion zum Testen durch Ersetzen des letzten u anzeigen.
Bei den Headern habe ich "etwas herumgehampelt" ... es geht am Schluss wieder einmal um das Zusammensetzen von 2 Bereichen. Und das geht evtl. auch schlanker.
Array: Zu sortierender Bereich
Keys: Erste Zelle eines 2x9-Bereichs für bis zu 9 Sortierschlüssel (oben: Feldnr.; unten: Sortierrichtung 0 auf, 1 ab)
Header: 1 bedeutet "enthält Feldnamen", 0 oder leer bedeutet "enthält keine Feldnamen".
Motivation zu der Funktion:
4 Mängel von SORTIERENNACH()
- Wie bei den anderen dynamischen Funktionen auch kann man keine Feldnamen mit einschließen, die unsortiert bestehen bleiben. Feldnamen sind jedoch Voraussetzung für fast alle älteren Excelfunktionen wie Autofilter, Spezialfilter und Pivot. Da wundere ich mich schon die ganze Zeit drüber! Ich muss die doch mit dem Bezug =A15# komplett versorgen können. Außerdem habe ich gern eine Spaltenbezeichnung über den Daten.
- Wie bei anderen Funktionen auch, z.B. WAHL oder allen ...WENNS-Funktionen, muss man die variabel vielen Argumente der Funktion immer einzeln versorgen.
- SORTIERENNACH erlaubt kein Leerlassen der Sortierrichtung; es muss bei jedem Begriff 1 oder -1 eingetragen werden. Ich finde 0 (oder leer) für aufsteigend und 1 für absteigend besser, weil ich schneller Entf drücke, als 1 ENTER. Außerdem sieht man beim Aufsteigend-Leerlassen den Unterschied zur Absteigend-1 auch optisch viel besser.
- Und schließlich sind für mich Spaltennummern ggü Spaltenbezügen viel flexibler. Sie können auch kalkuliert werden (im Gegensatz zur Teilwiederholung von Adressen, die - nun vollends unverständlich! - noch nicht mal als B1 ausreichen, sondern als B1:B10 eingegeben werden müssen). Da wurde nicht zuende gedacht.
Ausstattung von SORTBY.KEYRANGE
Daher steuere ich die 18 Sortierparameter einzeln zugewiesen in die LET-(bzw. SORTIERENNACH)-Funktion; das bedeutet 1 bis 9 Sortierungen auf einen Schlag, die wohl noch niemand benötigt hat (falls doch: Funktion einfach schachteln). Das Feld "Keys" verwaltet dies in 2 Zeilen x 9 Spalten, die leer bleiben müssen, wenn sie nicht alle benötigt werden.
Code:
Getränk Farbe Geschmack Herkunft A1:D10: Array
Wein rot süß Frankreich
Wein rot süß Deutschland
Wein rot trocken Frankreich
Wein rot trocken Deutschland
Wein weiß halbtrocken Frankreich
Wein weiß halbtrocken Deutschland
Wein weiß trocken Frankreich
Wein weiß trocken Deutschland
Bier hell hopfig Belgien
A12: Keys (nur erste Zelle A12 als Argument angeben!)
1 2 4 3 (dass hier 4 genannt werden, ist nur Zufall)
1 1 Bei A12 muss A12:I13 reserviert sein.
Getränk Farbe Geschmack Herkunft A15: =SORTBY.KEYRANGE(A1:D10;A12;1)
Bier hell hopfig Belgien
Wein weiß trocken Deutschland
Wein weiß halbtrocken Deutschland
Wein weiß trocken Frankreich
Wein weiß halbtrocken Frankreich
Wein rot trocken Deutschland
Wein rot süß Deutschland
Wein rot trocken Frankreich
Wein rot süß Frankreich
Bereich "Keys"
Oberste Sortierung: Getränk [1] wird aufsteigend [leer] sortiert
dahinter: Farbe [2] wird absteigend [1] sortiert
dahinter: Herkunft [4] wird aufsteigend [1] sortiert
dahinter: Geschmack [3] wird absteigend [leer] sortiert (wie man sieht, greift dieser Untersort im Beispiel sogar noch)
Lambda-Funktion
=LAMBDA(Array;Keys;Header;LET(
a;Array;
p;Keys;
t;Header;
offs;BEREICH.VERSCHIEBEN(p;;;2;9);
h;WENN(SEQUENZ(2)=2;1-offs*2;offs);
L;SEQUENZ(ZEILEN(a));
m;SEQUENZ(ZEILEN(a)-t;;1+t);
n;SEQUENZ(;SPALTEN(a));
o;SEQUENZ(;SPALTEN(h));
j;INDEX(h;1;o);
k;INDEX(h;2;o);
s;SORTIERENNACH(INDEX(a;m;n);
INDEX(a;m;WENNFEHLER(1/(1/INDEX(j;1));INDEX(j;1)));WENN(ISTFEHLER(INDEX(j;1));INDEX(k;1);INDEX(k;1));
INDEX(a;m;WENNFEHLER(1/(1/INDEX(j;2));INDEX(j;1)));WENN(ISTFEHLER(INDEX(j;2));INDEX(k;1);INDEX(k;2));
INDEX(a;m;WENNFEHLER(1/(1/INDEX(j;3));INDEX(j;1)));WENN(ISTFEHLER(INDEX(j;3));INDEX(k;1);INDEX(k;3));
INDEX(a;m;WENNFEHLER(1/(1/INDEX(j;4));INDEX(j;1)));WENN(ISTFEHLER(INDEX(j;4));INDEX(k;1);INDEX(k;4));
INDEX(a;m;WENNFEHLER(1/(1/INDEX(j;5));INDEX(j;1)));WENN(ISTFEHLER(INDEX(j;5));INDEX(k;1);INDEX(k;5));
INDEX(a;m;WENNFEHLER(1/(1/INDEX(j;6));INDEX(j;1)));WENN(ISTFEHLER(INDEX(j;6));INDEX(k;1);INDEX(k;6));
INDEX(a;m;WENNFEHLER(1/(1/INDEX(j;7));INDEX(j;1)));WENN(ISTFEHLER(INDEX(j;7));INDEX(k;1);INDEX(k;7));
INDEX(a;m;WENNFEHLER(1/(1/INDEX(j;8));INDEX(j;1)));WENN(ISTFEHLER(INDEX(j;8));INDEX(k;1);INDEX(k;8));
INDEX(a;m;WENNFEHLER(1/(1/INDEX(j;9));INDEX(j;1)));WENN(ISTFEHLER(INDEX(j;9));INDEX(k;1);INDEX(k;9)));
u;WENN(t;WENN(L=1;INDEX(a;1;n);INDEX(s;L-1;n));s);
u))
Das u am Schluss definiere ich zunächst, um es dann einzeln als Funktions-Rückgabe nochmals zu schreiben. Vorteil: Man kann alle Zwischenschritte der Funktion zum Testen durch Ersetzen des letzten u anzeigen.
Bei den Headern habe ich "etwas herumgehampelt" ... es geht am Schluss wieder einmal um das Zusammensetzen von 2 Bereichen. Und das geht evtl. auch schlanker.
WIN/MSO schicken angeblich alle 5 Sekunden Deinen Screen heim zu Papa (recall-Klausel).