Aller au contenu
  • 0
EGC

ListeValeurs(ListeNomrubriques)

Question

Ca y est, je me met à la fonction récursive :dur:pour la première fois. 

ça a l'air tentant , mais bon , je pédale un peu

J'aimerais établir une liste des valeurs de rubriques d'un enregistrement séparé par "|" ;

J'ai une liste des noms des rubriques de cette table et voila ...:crying:

 

Partager ce message


Lien à poster
Partager sur d’autres sites

21 réponses à cette question

Messages recommandés

  • 1
Le 22 septembre 2016 à 19:43, Philippe ROTTIER a dit :

Les fonctions récursives, je ne sais toujours pas les construire. Je me contente de les recopier...
 

 

Salut Philippe et tous :)

Oui, les fonctions récursives ne sont pas vraiment évidentes à comprendre et à maîtriser.

J'ai découvert cette technique il y a quelques années et je ne peux pas dire que j'en sois devenu un expert depuis, même si avec un peu de pratique on arrive à l'apprivoiser un minimum.

Alors, je ne vais pas faire un tuto, pas assez qualifié pour ça, et puis, il y a pas mal de ressources très intéressantes et complètes sur le Web (même si la plupart du temps je les trouve un peu trop techniques).

Donc, avant de passer aux codes, voici trois principes de base qu'il faut bien retenir concernant les fonctions récursives :

  1. Une fonction récursive est un bout de programme qui s'appelle lui-même ;
  2. Un code récursif ne se comporte, après tout, que comme une simple boucle ;
  3. Seule règle absolue et immuable (tous langages confondus) : toujours prévoir une condition d'arrêt (sans ça, c'est le plantage assuré :blink: ).

Le compteur

Ok, pour voir en toute simplicité ce qu'est la récursivité, je propose de voir comment faire un simple compteur, un peu bizarre, pour ne pas dire "inutile", puisque notre compteur ne fera qu'une simple itération d'une variable d'un numéro de départ jusqu'à un numéro de fin… 

Bon, c'est sûr, ce n'est vraiment pas très intéressant, mais c'est juste pour pouvoir aborder les principes de la récursivité avec quelque chose de très très basique.

Nous partons du principe que notre compteur commencera toujours par 0 (zéro).

La répétition

Si nous connaissons le numéro d'arrêt, par exemple 10, on peut faire notre compteur avec des simples variables :

$nro = 0 ;$nro = $nro + 1 ;$nro = $nro + 1 ;$nro = $nro + 1 ;$nro = $nro + 1 ;$nro = $nro + 1 ;$nro = $nro + 1 ;$nro = $nro + 1 ;$nro = $nro + 1 ;$nro = $nro + 1 ;$nro = $nro + 1 ;= 10

Bien-sûr, si notre numéro d'arrêt est 100 ou 1000 par exemple (ou pire), ça va être un peu chiant de construire notre compteur avec cette méthode… et ce serait un peu absurde de faire de l'informatique comme ça, non ? :P

La boucle

Il s'agit d'un bout de code qui va s'exécuter automatiquement un certain nombre de fois. 

Dans la plupart des langages, il y a plusieurs types de boucles : infinie, avec compteur, tant que, jusqu'à, etc., dans FileMaker, nous n'avons que la boucle infinie et, entre nous, cela va nous aider pour bien comprendre les fonctions récursives.

Donc, avec une boucle, rien de plus simple pour faire notre compteur :

$nro = 0 ;Boucle    Fin de boucle si ( $nro = 10 ) ;    $nro = $nro + 1 ;Fin de boucle= 10

Nous avons ici donc une boucle infinie qui réclame, dans tous les cas, d'avoir une condition d'arrêt pour éviter de planter FileMaker… et, jusqu'à là, je pense que nous maîtrisons tous ces techniques… nous pouvons donc avancer.

La fonction récursive

Comme dit dans les principes de base, une fonction récursive ne l'est que lorsqu'elle s'appelle elle-même, et, comme pour la boucle infinie, il faudra toujours prévoir une condition d'arrêt pour éviter le plantage.

Dans FileMaker, créons donc une fonction que nous nommerons "Compteur", elle recevra un seul paramètre "nro", puis entrons le code suivant :

Si ( nro = 10 ; nro ; Compteur ( nro + 1 ) )

Puis on appelle la fonction dans une formule de calcul de FileMaker :

Compteur ( 0 )= 10

Voilà, nous avons un compteur identique à celui de la boucle mais avec une fonction récursive.

Le code de cette fonction est vraiment très simple : 

  • une structure conditionnelle "Si", avec la condition d'arrêt "nro = 10" ; 
  • si la condition se confirme, alors on retourne la valeur de "nro" et tout s'arrête là ;
  • sinon, on appelle une nouvelle fois la fonction "Compteur" avec, comme paramètre, une simple itération de la variable "nro", et ceci va se re-exécuter jusqu'à la condition d'arrêt.

Pour aller au bout de notre compteur, ajoutons la possibilité d'avoir une limite d'arrêt variable, et d'abord avec une simple boucle :

$nro = 0 ;$fin = 25 ;Boucle    Fin de boucle si ( $nro = $fin ) ;    $nro = $nro + 1 ;Fin de boucle= 25

Finalement, avec notre fonction récursive, a laquelle on doit lui ajouter un paramètre "fin" :

Si ( nro = fin ; nro ; Compteur ( nro + 1 ; fin ) )

Et on l'appelle ainsi :

Compteur ( 0 ; 25 )= 25

 

Voilà, il y a bien-sûr d'autres subtilités à explorer pour bien maîtriser ces techniques récursives, mais les bases sont bien celles qu'on vient de voir… il ne reste plus qu'à les mettre en pratique… 

Si jamais on venait à développer d'avantage ce sujet, il faudrait ouvrir un nouveau fil de discussion, en attendant, allez'y, testez un peu tout ça, faut bien se lancer… ;)

...

 

Partager ce message


Lien à poster
Partager sur d’autres sites
  • 0

Bonjour, c'est tout simple :

substituer ( liste ( MaTable::MaRubrique ) ; "¶" ; "|" )

Partager ce message


Lien à poster
Partager sur d’autres sites
  • 0

Trop simple Philippe,

Je pars des noms de rubriques que j'ai dans une liste. 

Je pourrais faire substituer ( liste ( ResultatRubrique(MaTable::MaRubrique )) ; "¶" ; "|" ) , mais il faut que je le fasse pour chaque rubrique du modèle.

et cette fonction s'appliquera à 4 tables. 

 c 'est pour ça que j'ai pensé à une récursive. 

Partager ce message


Lien à poster
Partager sur d’autres sites
  • 0

On revient un peu à la discussion http://www.fmsource.com/index.php?/topic/54680-nombre-de-rubriques-remplies-dans-une-table/.

Il n'y a en tout cas pas besoin de recursion ici. Il est très facile d'obtenir le contenu d'une liste de rubriques .

 

ExecuteSQL ( " SELECT  * FROM MyTable WHERE IdMyTable = ? " ; "" ; "" ; IdMyTable )

ou 

Evaluate (" List ( "&Substitute ( $MaListeDeNomDeRubriques ; "¶" ; " ; " )&" ) ")

La question est simplement de décider comment on veut obtenir la liste des noms des rubriques, et si on veut vraiment toutes les rubriques. On peut coder la liste des rubriques en dur, l'obtenir avec ExecuteSQL ( "SELECT FROM FileMaker_Fields... ) ou bien à l'aide de la fonction FieldNames ( fileName ; layoutName ). Par exemple.

Comment est-ce que vous définissez votre liste des noms des rubriques? Où est-ce qu'elle est stockée ? Dans une rubrique, une liste de valeurs, fonction personnalisée... ?

 

Partager ce message


Lien à poster
Partager sur d’autres sites
  • 0

Ah ben oui c'est plus simple que je croyais avec la formule de fabrice, (je suis pas trop chaud pour me mettre au SQL.) Ma liste de rubrique vient d'un modèle

Definir ([
    _ListeNoms = $$Maliste ;    
$eval = "Liste ( " & Substituer ( _ListeNoms ; ¶ ; ";" ) & ")" ;
    _result = Substituer ( Evaluation ( $eval ); ¶; "|") ;
    $eval = ""
];
    _result
)

Dans cette formule, plusieurs choses que je comprends pas. 

la mise à zéro de $eval

Et la fonction Evaluation, j'ai beau lire et relire la doc, je ne vois toujours pas la logique des guillemets:dur:

 

merci:)

Partager ce message


Lien à poster
Partager sur d’autres sites
  • 0

Bonsoir,

Les fonctions récursives, je ne sais toujours pas les construire. Je me contente de les recopier... Et je suis toujours plein d'admiration pour tous ceux qui les maîtrisent.

Pour la fonction Evaluation, c'est plus simple : tu construis ta formule avec des morceaux de texte entre guillemets que tu concatennes avec des rubriques et la fonction Evaluation te recrache le résultat.

Dans la formule : "Liste ( " & Substituer ( _ListeNoms ; ¶ ; ";" ) & ")", tu ne peux pas écrire : Liste ( Substituer ( _ListeNoms ; ¶ ; ";" ) ), ça coince mais avec Evaluation ça marche. Magique !
 

Partager ce message


Lien à poster
Partager sur d’autres sites
  • 0

C 'est ça, c'est de la magie et on ne connait pas les secrets du tour.

:)

Partager ce message


Lien à poster
Partager sur d’autres sites
  • 0

Le secret du tour c'est que evaluation donne le contenu de la rubrique ou variable concernée, là où la fonction utilisée se contenterait d'en prendre le nom.

dans Substituer ( Texte ; ChaîneRecherche ; ChaîneRemplacement ), le premier critère est du texte et non pas une rubrique, il faut donc interpréter $eval pour en extraire le texte (le contenu).

Partager ce message


Lien à poster
Partager sur d’autres sites
  • 0

C'est parfaitement clair, un vrai tuto 

allons y pour le test :dur:

 

Partager ce message


Lien à poster
Partager sur d’autres sites
  • 0

 

Merci pour la clarté des explications, je vais aussi revisionner les vidéos de Fabrice de 2010 http://www.1-more-thing.com/fonctions-personnalisees-12/ et  http://www.1-more-thing.com/fonctions-personnalisees-ii/ et puis me lancer à mon tour.

 

Partager ce message


Lien à poster
Partager sur d’autres sites
  • 0

Salut tous :)

Bon, je pense que vous avez rectifié par vous-même la petite erreur qui m'a échappé sur me codes, il faudrait juste remplacer, dans les différentes conditions booléennes, l'opérateur supérieur ">" par l'opérateur égal "="... et oui, quand je vous disais que je n'étais pas un spécialiste de la récursivité... et, visiblement, tout aussi mauvais pour les boucles... :huh:

PS. ça m'apprendra à publier des codes sans les avoir testé... :)

[edit]
Bon, pour éviter que quelqu'un ne tombe sur des codes bugués (et qu'il n'est éventuellement quelques pensées trop "polies" à mon égard :blink: ), je viens de les corriger... merci à tous pour votre indulgence.
[/edit]

Partager ce message


Lien à poster
Partager sur d’autres sites
  • 0

Bon, maintenant ça y est, je sais faire des bloucles à mes lacets de chaussure ! :bien:

Pour le >, j'avais déjà corrigé, je met toujours un ≥. Une manie de parano, des fois qu'il ne s'arrête pas au = !!! Les bretelles et la ceinture... :w00t:

J'ai fait le petit exercice de Fredo, merci au passage, et j'ai joint une petite récursive bien documentée et didactique que j'ai glanée sur Internet et qui permet de faire des listes.

RECURSIVE.fmp12

RECURSIVE.fmp12

RECURSIVE.fmp12

RECURSIVE.fmp12

RECURSIVE.fmp12

RECURSIVE.fmp12

Partager ce message


Lien à poster
Partager sur d’autres sites
  • 0
Le 23/09/2016 à 10:38, Rodolf a dit :

Le secret du tour c'est que evaluation donne le contenu de la rubrique ou variable concernée, là où la fonction utilisée se contenterait d'en prendre le nom.

dans Substituer ( Texte ; ChaîneRecherche ; ChaîneRemplacement ), le premier critère est du texte et non pas une rubrique, il faut donc interpréter $eval pour en extraire le texte (le contenu).

Donc en fait la fonction Evaluation fait le même boulot que ResultatRubrique, mais dans une liste ?

Partager ce message


Lien à poster
Partager sur d’autres sites
  • 0
Le 24/09/2016 à 09:07, Philippe ROTTIER a dit :

J'ai fait le petit exercice de Fredo, merci au passage, et j'ai joint une petite récursive bien documentée et didactique que j'ai glanée sur Internet et qui permet de faire des listes.

J'ai rajouter un chrono. 

par boucle pour 10000; 660 ms

par la récursive 538 ms

ça a l'air plus rapide non ! 

Partager ce message


Lien à poster
Partager sur d’autres sites
  • 0
il y a 22 minutes, EGC a dit :

J'ai rajouter un chrono. 

par boucle pour 10000; 660 ms

par la récursive 538 ms

ça a l'air plus rapide non ! 

Eric,

Les vitesses d'exécution sont en effet très proches, mais attention, pour les fonctions récursives, cela dépend du nombre de tours de boucle et de la taille des données utilisées dans la "pile", sachant que FileMaker impose une limite de 50 000 appels récurrents mais que, bien avant d'atteindre cette limite, on peut parfois constater des ralentissements importants, suivant l'état de la "pile"...

Bref, dans l'idéal, la récursivité est à utiliser dans les cas où on peut maîtriser un minimum le nombre de tours à effectuer et la quantité de données qui vont être traitées... ce qui n'est pas toujours évident.

:)

Partager ce message


Lien à poster
Partager sur d’autres sites
  • 0

Je reviens à  cette formule qui fonctionne très bien, mais si une des rubriques est vide, le résultat n'en tient pas compte. Je sais pas trop ou inclure une condition sachant que l'évaluation se fait après avoir constituer la liste !

Definir ([
    _ListeNoms = $$Maliste ;    
$eval = "Liste ( " & Substituer ( _ListeNoms ; ¶ ; ";" ) & ")" ;
    _result = Substituer ( Evaluation ( $eval ); ¶; "|") ;
    $eval = ""
];
    _result
)

 

Partager ce message


Lien à poster
Partager sur d’autres sites
  • 0

Hello,

tu veux obtenir des lignes vides pour les rubriques de ta liste qui le sont (vides) ?

Alors peut-être en n'utilisant pas Liste () qui justement se débarasse des vides, mais en écrivant simplement dans ton "Définir" :

$eval = Substituer ( _ListeNoms ; ¶ ; "&¶&" ) ;

Partager ce message


Lien à poster
Partager sur d’autres sites
  • 0

Bonjour Laurent;

J'ai essayer différentes façons d'inclure ta formule dans Evaluation mais sans réussir. 

Faut dire que l’association de "Evaluation" avec une liste n'a pas encore percuter dans mon esprit, :dur:

Partager ce message


Lien à poster
Partager sur d’autres sites
  • 0

toutes mes confuses, il faut bien-sûr échapper le retour chariot pour qu'il soit conservé dans la chaîne de texte à passer à Evaluer () :

$eval = Substituer ( _ListeNoms ; ¶ ; "&\¶&" ) ;

Partager ce message


Lien à poster
Partager sur d’autres sites
  • 0

Pour Evaluation (), en complément de ce qu'ont dit Philippe et Rodolphe, j'ajouterai pour essayer de t'éclairer :

on lui passe une chaîne de texte qui peut en fait être interprétée par le moteur de calcul de FMP, de la même manière que si tu écrivais toi-même le calcul.

Par exemple ici, si tu voulais obtenir ta liste (des valeurs finales) directement dans le dataviewer, tu écrirais :

Table::Rubrique1 & ¶ & Table::Rubrique2 & ¶ & Table::Rubrique3
(si tu veux garder les valeurs vides, sinon Liste (
Table::Rubrique1 ; Table::Rubrique2 ; Table::Rubrique3 ) )

L'exercice est maintenant d'écrire les choses pour obtenir une chaîne de texte valant exactement la ligne ci-dessus (bien que moi, je me sois épargné les espaces, mettons-les ici)
Comme dit, j'échappe les retours chariots.

"Table::Rubrique1 & \¶ & Table::Rubrique2 & \¶ & Table::Rubrique3"

Comme tu disposes visiblement d'une liste de tes noms de rubrique, donc concrètement
"Table::Rubrique1
Table::Rubrique2
Table::Rubrique3"

il suffit d'y remplacer les retours chariots par " & \¶ & " pour obtenir la chaîne de texte voulue.
(ici on échappe ¶ car on veut qu'il "survive" jusqu'à Evaluation () : c'est elle qui doit le voir, comme le ferait ta fenêtre calcul du dataviewer)
Le principe est le même pour la version avec Evaluation ( "Liste (" ...

Partager ce message


Lien à poster
Partager sur d’autres sites
  • 0

Ah ok c 'est mieux avec l'échap.

Oui c 'est ça, il faut se souvenir que Evaluation évalue une chaine de texte et imaginer le resultat de la liste sous forme de texte. ça commence à percuter :drop:

En parallèle j'ai fais une récursive avec les conseils de Fredo et le tuto de David. 

 

ListeValeurs(ListRub;I;ListVal)

Definir([

_L=ListRub  ;
_D=DecompteValeurs( _L );

_i=Cas(EstVide(I) ; 1 ; I+1) ;

_Val = ListVal    &  ResultatRubrique (ObtenirValeur ( _L ; _i) ) & "|" 
 ];

Cas(_i = _D; _Val;   ListeValeurs(_L; _i;_Val ))

)

 

 

Liste.fmp12

Liste.fmp12

Liste.fmp12

Liste.fmp12

Liste.fmp12

Liste.fmp12

Liste.fmp12

Partager ce message


Lien à poster
Partager sur d’autres sites

Créer un compte ou se connecter pour commenter

Vous devez être membre afin de pouvoir déposer un commentaire

Créer un compte

Créez un compte sur notre communauté. C’est facile !

Créer un nouveau compte

Se connecter

Vous avez déjà un compte ? Connectez-vous ici.

Connectez-vous maintenant

  • En ligne récemment   0 membre est en ligne

    Aucun utilisateur enregistré regarde cette page.

×