[LAMBDA] Eindeutige Liste mit Berücksichtigung von Groß- und Kleinschreibung
#1
Moin,

angenommen, es würde eine eindeutige Liste von Werten benötigt, die jedoch Groß- und Kleinschreibung berücksichtigt.
Wie sicher bekannt, unterscheidet EINDEUTIG nicht zwischen Groß und Klein, weshalb die Funktion in diesem Fall wohl
nicht verwendet werden kann.

   

Folgend zwei Möglichkeiten. Beide Möglichkeiten nutzen IDENTISCH zum Vergleich der Werte. Die erste Formel ist
etwas länger und verwendet Matrizen zum Vergleich. Die zweite verwendet REDUCE und dadurch implizit eine Rekursion.
Man könnte auch eine eigene rekursive LAMBDA-Funktion schreiben, REDUCE ist aber hier wesentlich eleganter.

Die erste Formel basiert darauf, dass die einzelnen Elemente der Liste mit der gleichen, jedoch transponierten Liste
verglichen und eine Matrix anhand von MATRIXERSTELLEN erstellt wird. Hierbei wird nur der Bereich oberhalb der Diagonale
in der Matrix berücksichtigt. Diese Matrix wird anschließend mit einer Einser-Reihe multipliziert, um aus der Matrix eine
Zeile zu machen. Danach wird das Ergebnis mit 1 verglichen und mit dem Index der Listenelemente multipliziert, was als
Ergebnis die Indizes ergibt, die zu berücksichtigen sind. Die anderen sind Null. Der Rest ist dann recht simpel:
Filtern und Listenelemente extrahieren und wieder transponieren.

PHP-Code:
=LET(Daten;$B$3:$B$11;N;ZEILEN(Daten);M;SEQUENZ(1;N)*(MMULT(SEQUENZ(1;N;1;0);MATRIXERSTELLEN(N;N;
 
LAMBDA(X;Y;WENN(X>Y;0;--(IDENTISCH(INDEX(Daten;X;1);INDEX(Daten;Y;1)))))))=1);
 
MTRANS(INDEX(Daten;FILTER(M;M>0);1))) 

Die zweite Formel verwendet REDUCE und VSTACK. REDUCE sorgt dafür, dass alle Elemente der Liste durchlaufen werden
und dabei der Vorgängerwert berücksichtigt wird. Das interessante ist übrigens, dass das auch mit Arrays funktioniert.
Das Array wächst hier bei jedem Durchlauf - je nachdem, ob der aktuell iterierte Wert aus der Ausgangsliste
im Array des zuvor durchlaufenen Schrittes enthalten ist oder nicht. Das Anhängen macht dann VSTACK.
Die Formel stammt nicht von mir, finde diese aber sehr elegant.

PHP-Code:
=REDUCE(;$B$3:$B$11;LAMBDA(A;V;WENN(SUMME(--IDENTISCH(A;V))>0;A;VSTACK(A;V)))) 

Interessant wäre mal herauszufinden, wie sich beide Formeln bei sehr großen Listen verhalten; bspw. bei der Performance.

Gruß
Microsoft Excel Expert · Microsoft Most Valuable Professional (MVP) :: 2011-2019 & 2020-2022 :: 10 Awards
https://de.excel-translator.de/translator :: Online Excel-Formel-Übersetzer :: Funktionen :: Fehlerwerte :: Argumente :: Tabellenbezeichner
[-] Folgende(r) 2 Nutzer sagen Danke an maninweb für diesen Beitrag:
  • PIVPQ, schauan
Antworten Top
#2
Hallo maninweb, interessant (bin länger weg, kann erst dann genauer gucken)!
WIN/MSO schicken angeblich alle 5 Sekunden Deinen Screen heim zu Papa (recall-Klausel). 
Antworten Top
#3
Das REDUCE ist (theoretisch) schon eine tolle Sache. 

Hier noch eine rechnerische Lösung ohne Rekursion und ohne MMULT, aber mit EINDEUTIG:

=LET(f;B1:B100000;WEGLASSEN(EINDEUTIG(HSTAPELN(f;
NACHZEILE(f;LAMBDA(f;PRODUKT(LN(CODE(TEIL(f;SEQUENZ(LÄNGE(f));1)))*LN(SEQUENZ(LÄNGE(f))+1)/10)))));;-1))


Neben die Daten wird dabei temporär eine dafür fast absolut sicher eindeutige Gleitkommazahl gestellt, die sich aus ASCII-Code und Stelle im String jedes Zeichens ergibt.

Beim Mengentest ergibt sich anhand von B1# (100.000 Daten): 

=ZEICHEN(ZUFALLSMATRIX(100000;;65;122;1))
&ZEICHEN(ZUFALLSMATRIX(100000;;65;122;1))
&ZEICHEN(ZUFALLSMATRIX(100000;;65;122;1))
&ZEICHEN(ZUFALLSMATRIX(100000;;65;122;1)) (plattgemacht)

für 
ca. 0,6 Sekunden, normales EINDEUTIG, ca. 94500 Daten (als Performance-Vergleich)
ca. 1,5 Sekunden, meine Lösung, 99579 Daten
Nach 300 Sekunden gab ich REDUCE auf (vermutlich gibt es ein Ergebnis)
MMULT meldet Ressourcenüberschreitung

modifiziert auf 1/10, also 10.000 Daten:
13 Sekunden REDUCE, mit Rückgabe 9999 Daten (genau wie meine Lösung)
MMULT meldet Ressourcenüberschreitung

modifiziert auf 1/100, also 1.000 Daten:
70 Sekunden für MMULT
WIN/MSO schicken angeblich alle 5 Sekunden Deinen Screen heim zu Papa (recall-Klausel). 
[-] Folgende(r) 2 Nutzer sagen Danke an LCohen für diesen Beitrag:
  • schauan, maninweb
Antworten Top
#4
Moin,

bei den großen Daten stelle ich soeben dasselbe fest wie Du. Bin allerdings nun selber aus privaten
Gründen zeitlich eingeschränkt und eher sporadisch kurz hier, so wie jetzt. Kann also bei mir dauern.

Gruß
Microsoft Excel Expert · Microsoft Most Valuable Professional (MVP) :: 2011-2019 & 2020-2022 :: 10 Awards
https://de.excel-translator.de/translator :: Online Excel-Formel-Übersetzer :: Funktionen :: Fehlerwerte :: Argumente :: Tabellenbezeichner
Antworten Top
#5
Ich wollte gerade damit beginnen, die Lösung für ein Array (wie bei dem normalen EINDEUTIG funktionierend) anstelle nur einen Spaltenvektor zu erweitern.

Durch die Verwendung von NACHZEILE...PRODUKT wird aber als Nebeneffekt von vornherein schon die ganze Zeile logarithmisch multipliziert, nicht nur eine Zelle. Es reicht also weiterhin das Anhängen von nur dieser einen Kontroll-Gleitkommazahl-Spalte aus, anstelle eines ganzen Schattenarrays.

Auf den ersten Blick scheint es auch bei Leerzellen durch eine Leerzellenbehandlung (für 0 ungleich leer, da am Ziel ja leer auch zu 0 wird, wie bei jeder Formel) zu funktionieren:

EINDEUTIG.IDENT: =LET(f;A1:C9;WEGLASSEN(EINDEUTIG(HSTAPELN(f;
NACHZEILE(WENN(f="";"~^#°";f);LAMBDA(f;PRODUKT(LN(CODE(TEIL(f;SEQUENZ(LÄNGE(f));1)))*LN(SEQUENZ(LÄNGE(f))+1)/10)))));;-1))


Ohne die Leerzellenbehandlung ergibt das Zeilenprodukt einen Fehler #KALK!, und da der dann auch bei den Klein-Groß-unterschiedlichen Inhalten gilt, ergibt sich ein normales EINDEUTIG, was wir nicht wollen.
WIN/MSO schicken angeblich alle 5 Sekunden Deinen Screen heim zu Papa (recall-Klausel). 
[-] Folgende(r) 1 Nutzer sagt Danke an LCohen für diesen Beitrag:
  • maninweb
Antworten Top
#6
Um auch

Helga|helga|...
helga|Helga|...
Alle|alle|...
alle|Alle|...
...

(|=Spaltentrenner) zusammen korrekt als Zeilen zu erhalten, hier eine weitere Korrektur/Abwandlung:

=LET(f;A1:C9;WEGLASSEN(EINDEUTIG(HSTAPELN(f;
NACHZEILE(WENN(f="";"~^#°";f);LAMBDA(f;PRODUKT(
LET(g;TEXTVERKETTEN(;;f);h;SEQUENZ(LÄNGE(g));LN(CODE(TEIL(g;h;1)))+LN(h)/PI())
)))));;-1))


Das /PI() habe ich als Vorsichtsmaßnahme drin. Ist vermutlich nicht nötig.
WIN/MSO schicken angeblich alle 5 Sekunden Deinen Screen heim zu Papa (recall-Klausel). 
[-] Folgende(r) 1 Nutzer sagt Danke an LCohen für diesen Beitrag:
  • maninweb
Antworten Top


Gehe zu:


Benutzer, die gerade dieses Thema anschauen: 1 Gast/Gäste