%LOOKUP
Chercher une valeur dans un tableau
Cherche une valeur dans un tableau et renvoie sa position, ou 0 si elle n'y est pas ; les variantes LT, LE, GE et GT cherchent la valeur la plus proche dans un tableau trié.
Syntaxe
%LOOKUP(valeur : tableau {: départ {: nombre}})
%LOOKUPLT(valeur : tableau {: départ {: nombre}})
%LOOKUPLE(valeur : tableau {: départ {: nombre}})
%LOOKUPGE(valeur : tableau {: départ {: nombre}})
%LOOKUPGT(valeur : tableau {: départ {: nombre}})
valeur- Ce qu'on cherche, du même type que les éléments du tableau.
tableau- Le tableau où chercher. Pour LT, LE, GE et GT, il doit être déclaré
ascendoudescendet réellement trié dans cet ordre. On ne peut pas y passer%subarr: on utilisedépartetnombre. départ- Position du premier élément examiné (1 par défaut). Le résultat reste une position du tableau entier.
nombre- Nombre d'éléments examinés à partir de
départ(jusqu'à la fin du tableau par défaut). - Résultat
- Un entier : la position de l'élément trouvé, 0 si rien ne convient.
%LOOKUPcherche l'égalité exacte. Avec un tableau trié :LTl'élément le plus proche strictement inférieur,LEinférieur ou égal,GEsupérieur ou égal,GTstrictement supérieur.
À quoi ça sert
C'est la recherche dans un tableau : un code postal dans une liste de villes, un statut dans une liste de libellés. Le test s'écrit if %lookup('Brest' : villes) > 0.
Les variantes servent aux tables de tranches : remises selon le montant, taux selon la date. Avec les seuils 0, 1 000, 5 000, 20 000 et 50 000, %lookupLE(6000 : seuil) donne la tranche qui s'applique à 6 000.
Exemple 1 : Recherche exacte, départ et nombre d'éléments
**free
// %LOOKUP : chercher une valeur dans un tableau, position de depart et nombre d'elements.
ctl-opt dftactgrp(*no) actgrp(*new);
dcl-s villes char(12) dim(6);
dcl-s pos int(10);
villes(1) = 'Montpellier';
villes(2) = 'Lyon';
villes(3) = 'Brest';
villes(4) = 'Lyon';
villes(5) = 'Rennes';
villes(6) = 'Nantes';
pos = %lookup('Lyon' : villes);
snd-msg 'Premier Lyon : ' + %char(pos);
// Depart a l'element 3 : on trouve la seconde occurrence.
pos = %lookup('Lyon' : villes : 3);
snd-msg 'Lyon depuis 3 : ' + %char(pos);
// Depart a 5, sur 2 elements seulement (5 et 6).
pos = %lookup('Lyon' : villes : 5 : 2);
snd-msg 'Lyon dans 5 a 6 : ' + %char(pos);
// Valeur absente : 0.
pos = %lookup('Paris' : villes);
snd-msg 'Paris : ' + %char(pos);
// La casse compte, les blancs de fin non.
pos = %lookup('LYON' : villes);
snd-msg 'LYON en majuscule : ' + %char(pos);
if %lookup('Brest' : villes) > 0;
snd-msg 'Brest est dans la liste';
endif;
*inlr = *on;
Résultat réel, compilé et exécuté sur IBM i 7.5 :
Premier Lyon : 2
Lyon depuis 3 : 4
Lyon dans 5 a 6 : 0
Paris : 0
LYON en majuscule : 0
Brest est dans la liste
Sans autre paramètre, on obtient la première position (2). Avec un départ à 3, on trouve la seconde occurrence, en position 4 du tableau entier. En limitant la recherche aux éléments 5 et 6, on obtient 0. 'LYON' en majuscules n'est pas trouvé : la comparaison tient compte de la casse, alors que les blancs de fin de la zone sont ignorés.
Exemple 2 : Tranches avec LE, LT, GE et GT
**free
// %LOOKUPLT / LE / GE / GT sur un tableau numerique trie en ordre croissant.
ctl-opt dftactgrp(*no) actgrp(*new);
// Seuils de remise : le tableau doit etre trie, ce que ascend declare.
dcl-s seuil packed(7:0) dim(5) ascend;
dcl-s pos int(10);
seuil(1) = 0;
seuil(2) = 1000;
seuil(3) = 5000;
seuil(4) = 20000;
seuil(5) = 50000;
// LE : plus grand seuil inferieur ou egal a la valeur (tranche de remise).
pos = %lookuple(6000 : seuil);
snd-msg 'LE 6000 : element ' + %char(pos) + ' = ' + %char(seuil(pos));
pos = %lookuple(5000 : seuil);
snd-msg 'LE 5000 : element ' + %char(pos);
// LT : strictement inferieur.
pos = %lookuplt(5000 : seuil);
snd-msg 'LT 5000 : element ' + %char(pos);
// GE : plus petit seuil superieur ou egal.
pos = %lookupge(6000 : seuil);
snd-msg 'GE 6000 : element ' + %char(pos);
// GT : strictement superieur.
pos = %lookupgt(50000 : seuil);
snd-msg 'GT 50000 : element ' + %char(pos);
// Aucun seuil inferieur a -1 : 0.
pos = %lookuple(-1 : seuil);
snd-msg 'LE -1 : element ' + %char(pos);
*inlr = *on;
Résultat réel, compilé et exécuté sur IBM i 7.5 :
LE 6000 : element 3 = 5000
LE 5000 : element 3
LT 5000 : element 2
GE 6000 : element 4
GT 50000 : element 0
LE -1 : element 0
Le tableau des seuils est trié en ordre croissant et déclaré ascend. Pour 6 000, LE renvoie l'élément 3 (seuil 5 000) et GE l'élément 4 (20 000). Pour 5 000, LE et LT ne donnent pas le même résultat : la valeur exacte compte pour LE (élément 3), pas pour LT (élément 2). Enfin, aucun seuil n'est supérieur à 50 000, ni inférieur ou égal à -1 : le résultat est 0.
Exemple 3 : Éléments inutilisés et tableau non trié
**free
// Deux pieges de %LOOKUP : elements inutilises et tableau non trie.
ctl-opt dftactgrp(*no) actgrp(*new);
dcl-s clients char(10) dim(6);
dcl-s seuil packed(7:0) dim(5) ascend;
dcl-s pos int(10);
dcl-s nbUtilises int(10) inz(3);
// Piege 1 : 3 elements remplis sur 6, les autres sont a blanc.
clients(1) = 'Dupont';
clients(2) = 'Martin';
clients(3) = 'Leroy';
pos = %lookup(' ' : clients);
snd-msg 'Blanc, tout le tableau : ' + %char(pos);
pos = %lookup(' ' : clients : 1 : nbUtilises);
snd-msg 'Blanc, 3 premiers : ' + %char(pos);
// Piege 2 : le tableau est declare ascend mais rempli dans le desordre.
seuil(1) = 5000;
seuil(2) = 100;
seuil(3) = 20000;
seuil(4) = 50;
seuil(5) = 1000;
pos = %lookup(1000 : seuil);
snd-msg 'Desordre, 1000 (elem 5) : ' + %char(pos);
pos = %lookupge(900 : seuil);
snd-msg 'Desordre, GE 900 : ' + %char(pos);
// Apres tri, les resultats sont corrects.
sorta seuil;
pos = %lookup(1000 : seuil);
snd-msg 'Trie, 1000 : ' + %char(pos);
pos = %lookupge(900 : seuil);
snd-msg 'Trie, GE 900 : ' + %char(pos);
*inlr = *on;
Résultat réel, compilé et exécuté sur IBM i 7.5 :
Blanc, tout le tableau : 4
Blanc, 3 premiers : 0
Desordre, 1000 (elem 5) : 0
Desordre, GE 900 : 3
Trie, 1000 : 3
Trie, GE 900 : 3
Sur les 6 éléments, 3 sont vides. Chercher un blanc renvoie 4 : c'est le premier élément inutilisé. Avec le nombre d'éléments utiles (nbUtilises) en dernier paramètre, le résultat est 0.
Le second tableau est déclaré ascend mais rempli dans le désordre : 1000 est bien présent (élément 5) et n'est pas trouvé, et GE 900 renvoie l'élément 3 (20 000) au lieu de l'élément 5. Après sorta, les deux réponses sont justes.
Le piège
Deux erreurs silencieuses, sans message. D'abord, les éléments inutilisés d'un tableau sont des valeurs comme les autres : chercher un blanc ou un zéro tombe dessus. Il faut passer départ et nombre, comme dans le troisième exemple, pour ne regarder que la partie remplie.
Ensuite, un tableau déclaré ascend ou descend n'est pas trié pour autant : le compilateur fait confiance à la déclaration. Sur un tableau rempli dans le désordre, même une recherche exacte peut rater une valeur présente (1000 dans l'exemple). Pour LT, LE, GE et GT, le compilateur refuse un tableau sans ascend ni descend (erreur RNF0592) ; c'est à nous de trier avant, avec sorta.