Unique Values

De unieke waarden uit een lijst overhouden

Er zijn diverse functies op internet te vinden waarmee je uit een lijst met waarden de unieke waarden kunt filteren. Die functies missen  case-sensitivity of ze zijn niet autonoom en dat heeft de functie die ik hier voorstel wél.

De custom-functie heet UniqueValues en ziet er als je hem gebruikt zo uit:

UniqueValues( Valuelist ; CaseSensitive ; Result )

LET OP! Dit is een nieuwe variant van de functie die tot 15 Augustus 2014 hier heeft gestaan.

  • Valuelist bevat de waardelijst die je wilt “ontdubbelen”
  • CaseSensitive bevat 1 of 0 en daarmee geef je aan of onderscheid tussen hoofd- en kleine letters moet worden gemaakt
  • Result kan je leeglaten, maar mag worden gevuld een startwaarde

Let ( [
    this = GetValue ( Valuelist ; 1 ) ;
    tCnt = ValueCount ( Valuelist ) ;
    tSpc = “$@space@$” ;
    rList = Case (
    CaseSensitive = 0 ;
    Substitute ( RightValues ( Valuelist ; tCnt-1 ) ; [ ” ” ; tSpc ] ; [ ¶ ; ” ” ] ) ;
    CaseSensitive = 1 ;
    Substitute ( ¶ & RightValues ( Valuelist ; tCnt-1 ) & ¶ ;
            [ ¶ ; “¶¶” ] ; [ ¶ & this & ¶ ; ¶ ] ; [ ” ” ; tSpc ] ; [ ¶ ; ” ” ] ) ) ;
    Rest = Substitute ( TrimAll ( rList ; 1 ; 1 ) ; [ ” ” ; ¶ ] ; [ tSpc ; ” ” ] ) ;
    pCnt = If ( CaseSensitive = 0 ; PatternCount ( ¶ & Result & ¶ ; ¶ & this & ¶ ) ; 0 ) ;
    Result = Result & If ( pCnt = 0 and this ≠ “” ; If ( Result ≠ “” ; ¶ ) & this )
] ;
    If ( Rest = “” ; Result ; UniqueValues ( Rest ; CaseSensitive ; Result ) )
)

Twee voorbeelden met dezelfde invoer, met als enige verschil géén respectievelijk wél hoofdlettergevoelig:

  1. Invoer:
    UniqueValues ( “a¶A¶C¶D¶a¶b¶c¶D” ; 0 ; “” )
    Resultaat:
    a
    C
    D
    b
  2. Invoer
    UniqueValues ( “a¶A¶C¶D¶a¶b¶c¶D” ; 1 ; “” )
    Resultaat:
    a
    A
    C
    D
    b
    c

Je ziet aan het resultaat dat de functie gewoon rechtuit gaat. Zodra een tot dan toe onbekende waarde wordt tegengekomen, wordt die in de resultaatlijst geplaatst. Daarna wordt deze waarde niet meer overschreven.

De grap van deze functie zit in de opbouw van de berekening voor de variabelen rList , Rest en pCnt (=patroontelling).

Wanneer hoofdlettergevoeligheid aan staat, dan worden in rList met Substitute() (die vervangt alleen de exact overeenkomende tekst) alle exacte occurrences van de eerste waarde uit de Valuelist vervangen door NULL/een lege waarde. Bij hoofdlettergevoeligheid uit wordt alleen de eerste waarde verwijderd. Daarna worden alle spaties omgezet in een dummywaarde en alle ¶ omgezet in spaties.

De volgende stap is alle overbodige spaties (dus eigenlijk alle ¶) verwijderen met TrimAll(). Daarna worden de spaties weer ¶ en de dummywaardes worden weer spaties, de lijst is weer normaal en wordt in de variable Rest gezet.

Wanneer de hoofdlettergevoeligheid uit staat, wordt met PatternCount() (niet hoofdlettergevoelig) het aantal occurrences in rList geteld. Bij hoofdlettergevoeligheid uit is het resultaat altijd 0.

Nu zijn alle voorbewerkingen klaar en kan het resultaat worden samengesteld in Result, dat blijft groeien, totdat de variable Rest geen waarde meer bevat en de functie kan worden afgesloten.

Tenslotte heb ik hier gekozen voor tail-recursion, daardoor kan een lijst met maximaal 50000 waarden worden ontdubbeld….. dat klopt niet helemaal. Het is waar wanneer je kiest voor CaseSensitive=0, dan heeft de functie geen andere keus dan alle waarden één voor één te evalueren. Kies je echter voor CaseSensitive=1 , dan is het aantal iteraties zo groot als dat het aantal unieke waarden is.

Als je nu weet dat de lijst die je hebt erg lang is en maar slecht een beperkt aantal waarden heeft, dan kan het zinvol zijn om eerst UniqueValues met CaseSensitive=1 te gebruiken en het resultaat vervolgens met CaseSensitive=0 te verwerken. Ik heb overigens wel overwogen dit standaard te doen, maar dat komt de snelheid niet ten goede.

Een voorbeeld van het bestand UniqueValues staat klaar voor je om te worden gedownload