Optimiser mon code, je dois chercher 3 mots qui font entre 20 et 70 caractères (strlen())

Le problème exposé dans ce sujet a été résolu.

Hello

Voici ma petite fonction PHP :

<?php
function gen_recherche()
{
    // Il y a environ 400 mots dans ce tableau
    $listes = ['mot'];


    // Cherche 3 mots aléatoires dans le tableau
    $a_rand = $listes[mt_rand(0, 400)];
    $b_rand = $listes[mt_rand(0, 400)];
    $c_rand = $listes[mt_rand(0, 400)];
    

    // Combine le tout
    $liste = $a_rand.$b_rand.$c_rand;


    // Vérifie si les mots combiner dépasse les 20 caractères et ne dépasse pas les 70 caractères
    if(strlen($a_rand.$b_rand.$c_rand) > 20 AND strlen($a_rand.$b_rand.$c_rand) < 70)
        $liste = gen_recherche();


    return $liste;
}

1ere problème :

En gros, faut pas que les 3 mots que je récupère ne compte pas plus de 70 caractères (en tout), et je ne peux pas couper la chaîne, que ce soit en PHP, ni CSS (en baissant la taille ou en coupant le texte par exemple).

Donc, c’est pas trop mal, mais le problème, c’est que c’est souvent lent, car il doit chercher les 3 bons qui feront entre 20 et 70 caractères.

2eme problème : je peux parfois avoir 2 mêmes mots, voir 3 (ça m’est déjà arrivé :O), alors je ne sais pas trop comment gérer se soucis.

Pourriez-vous me donner un petit conseil pour améliorer la fonction ?

+0 -0

Salut,

Je pense que pour commencer tu devrais trier ton tableau en fonction de la taille des chaînes, comme ça tu connaîtras les tailles minimales et maximales. Tu peux alors le filtrer pour supprimer celles qui seront dans tous les cas hors des bornes (car trop grandes une fois concaténées aux deux plus petites ou trop petites malgré la concaténation aux deux plus grandes).

Puis tu tires une chaîne au hasard que tu retires de la liste. Tu soustrais sa taille des bornes minimales et maximales et tu filtres à nouveau pour ne garder que les résultats possibles.

Tu peux alors recommencer les tirages et filtrages pour sortir les deuxième et troisième chaînes.

Plop,

Je ne suis pas sûr de comprendre l’intérêt (ou le but) de la fonction.

Pourquoi tirer au sort des éléments du tableau ?

MichelPro

Après, si on débat la dessus, on est pas sortit de l’auberge :P

C’est pour afficher des propositions aléatoires de termes recherches voilà, et donc ça peut être que aléatoire. Sinon il y aurai que 3 termes fixes.

@entwanne : impossible, il me faut vérifier toutes les chaînes, et il n’y aucune chaîne qui dépasse les limites.

Il peut y avoir 1 chaîne de 50 caractères et 2 chaînes de 10 par, il peut y avoir 1 chaîne de 25 car., 23 cars., et 8 cars. c’est vraiment pas du tout fixe, et je dois utiliser vraiment tous les éléments du tableau.

+0 -0

Il faut recommencer de zéro si les deux mots les plus courts restant rendent la chaîne trop longue.

tleb

Dans quel cas est-ce que ça arriverait ?

@entwanne : impossible, il me faut vérifier toutes les chaînes, et il n’y aucune chaîne qui dépasse les limites.

Il peut y avoir 1 chaîne de 50 caractères et 2 chaînes de 10 par, il peut y avoir 1 chaîne de 25 car., 23 cars., et 8 cars. c’est vraiment pas du tout fixe, et je dois utiliser vraiment tous les éléments du tableau.

Machou

Je ne comprends pas en quoi ça rend les choses impossibles.

Oui, c’est pour cela que je parle de filtrer à chaque étape pour enlever les mots trop courts ou trop longs.

Si un mot concaténé aux deux plus petits dépasse la taille max, il doit être filtré. De même si un mot concaténé aux deux plus grands est en-dessous de la taille minimale.

Et de façon équivalent à la deuxième étape en testant avec la taille du plus petit et du plus grand.

À la troisième étape il ne reste qu’à tester la taille du mot en lui-même.

@entwanne : je ne disais pas impossible dans ce sens, mais impossible que je le fasse, c’est impensable plutôt, car sinon je vais avoir toujours 3 valeurs pareils qui ne changeront jamais.

Peu importe si le 1er est plus long que le 2eme, ou 3eme, ou peu importe si le 2eme est plus petit que le 1er ou 3eme, tout ça on s’en fou en fin de compte, il ne faut pas que la chaîne en elle même dépasse les 70 chars.

Avec ma fonction j’ai donc fait un rappel via le if, mais c’est souvent assez lent, 1 à 5 secs, pour un chargement de page, c’est trop lent.

Ou alors ce que j’ai pensé, c’est de faire une mise en cache de toutes les combinaisons possibles.

  • je fais tourner un script PHP en cli pendant quelques heures
  • ou alors je laisse les visiteurs faire le travaille, au bout d’un moment ça sera terminé

Je compte aussi rajouter un autre tableau dans le lot, ou y’aura environ 200 entrées en plus, :/

Je vois que ça comme solution la plus rapide à mon goût.

+0 -0

Avec ma fonction j’ai donc fait un rappel via le if, mais c’est souvent assez lent, 1 à 5 secs, pour un chargement de page, c’est trop lent.

Machou

C’est pour ça que je te propose quelque chose de plus rapide qui donne les mêmes résultats : 3 mots tirés aléatoirement dans ton ensemble qui respectent les conditions que tu émets sur la taille.

Je ne vois pas pourquoi tu te retrouverais avec toujours les mêmes chaînes, à moins que ton générateur pseudo-aléatoire soit faussé (mais dans ce cas tu as le même problème avec ta solution actuelle).

Le problème de ta solution, c’est que tu ne traites la condition qu’au stade final, alors qu’elle pourrait être prise en compte dès le départ.

Pour faire une analogie vers un problème plus simple, c’est comme si tu voulais générer 10 nombres entre 1 et 10 (compris) tous différents. Tu génères un premier nombre, puis un deuxième, etc. et arrivé au dixième tu remarques qu’il y a des doublons donc tu recommences depuis le début en espérant que ça se passe mieux.
Alors que, dès le départ, tu peux faire en sorte de générer 10 nombres différents.

C’est ce que je fais, je tire trois mots aléatoirement, mais si la somme dépasse les 70 car. on recommence.

Je me retrouve pas souvent avec les mêmes mots, c’est rare, mais ça arrive. C’est si je ne tirerai pas les mots aléatoirement que je me retrouverai avec toujours les mêmes mots.

Du coup je peux faire comment ? car je comprends le principe mais j’arrive pas à le faire sur écrit :O

+0 -0

On va avancer tout doucement.

Dans ton dictionnaire de 400 mots, peux-tu nous dire combien tu as de mots de 5 lettres, combien de mots de 6 lettres, etc etc etc.

Pourquoi je demande ça ?

Imaginons que tes mots font tous entre 15 et 50 lettres.

Tu tires 3 mots au hasard. Si un de ces mots fait 41 lettres, ou plus de 41 lettres, c’est mort, ce n’est même pas la peine de regarder les 2 autres mots, on est sûr que la longueur totale fera plus de 70 caractères (41+15 +15, ça fait plus de 70)

C’était la première amélioration proposée par Entwanne, regardons déjà si cette amélioration donne quelque chose dans ton cas.

Edit

Je viens de lire ou de relire ton code, et en ligne 19/20, tu fais :

si longueur_cumulee > 20 et longueur_cumulée < 70 alors
   relancer_une_nouvelle_recherche()

C’est bien ça que tu fais ? Et donc tu fais exactement l’inverse de ce qu’il faut faire.

Je propose :

si longueur_cumulee < 20 ou longueur_cumulée > 70 alors
    relancer_une_nouvelle_recherche()
+4 -0

Je note au passage que tu n’as pas besoin de sélectionner aléatoirement ces trois mots, donc si tu appliques l’idée d’entwanne pour supprimer les mots trop grands, au bout d’un moment tu tombes sur un long mot qui avec les deux plus petits mots fait entre 20 et 70 caractères, que tu peux donc retourner.

Sinon tu peux créer des sous-groupes de mots de taille fixe. Il suffit dans cet ensemble de faire des tirages sur la liste des tailles possibles, puis ensuite de tirer aléatoirement dans les 3 groupes choisis.

Après tu peux tirer les trois tailles plus intelligemment pour être sûr de choisir une solution valable à chaque coups.

C’est ce que je fais, je tire trois mots aléatoirement, mais si la somme dépasse les 70 car. on recommence.

Je me retrouve pas souvent avec les mêmes mots, c’est rare, mais ça arrive. C’est si je ne tirerai pas les mots aléatoirement que je me retrouverai avec toujours les mêmes mots.

Machou

C’était un exemple, dans ton cas le problème c’est de tomber sur un résultat qui ne respecte pas les conditions initiales.

Du coup je peux faire comment ? car je comprends le principe mais j’arrive pas à le faire sur écrit :O

Machou

Comme j’ai l’impression qu’on ne se comprend pas, je vais illustrer la solution que je te propose, étape par étape.

  • Disons qu’on a une liste contenant comme valeurs 'x', 'xx', 'xxx', ..., 'x'*70, soit 70 mots de longueurs variables.
  • Dans un premier temps on peut filtrer les mots qui ne donneront jamais de solutions, c’est à dire les chaînes entre 'x'*68 et 'x'*70, car concaténées aux deux plus petites, elles seront toujours supérieures à la borne maximale.
  • Dans cet ensemble filtré, tu tires ensuite au hasard ton premier mot, disons 'xxxxx', que tu supprimes de la liste (ça évite de retomber dessus par la suite).
  • Maintenant, tu peux que la concaténation des deux mots restants soit comprise entre 15 et 65 caractères (puisque tu as tiré un mot de 5 lettres).
  • Tu peux alors filtrer les mots de 'x'*65 à 'x'*67 puisqu’ils seront hors limites (si on les concatène au plus petit mot, toujours).
  • Tu tires maintenant ton second mot, tu obtiens 'xx', tu le supprimes de la liste.
  • Il faut maintenant que la taille du dernier mot soit comprise entre 13 et 63 lettres (tu as tiré un mot de 2).
  • Donc tu filtres ta liste pour enlever tous les mots de moins de 13 lettres ou de plus de 63.
  • Dans ce qu’il te reste, tu peux tirer ton troisième mot.
  • Tu obtiens une solution qui respecte les conditions initiales et tu n’as pas besoin de relancer.

Si tu tries tes mots par taille croissante, au lieu de prendre au hasard dans tout le tableau, tu peux prendre au hasard seulement les mots qui ont une longueur comprise entre L1 et L2 (pas besoin de filtrer / changer le tableau).

Du coup ça suggère l’approche suivante :

  • prendre un mot au hasard, noter sa taille L1
  • prendre un mot au hasard de taille 0 <= L2 <= 70 - L1
  • prendre un mot au hasard de taille 20 - L1 - L2 <= L3 <= 70 - L1 - L2
  • si il n’y a pas de mot possible à une de ces étapes, recommencer

C’est naïf mais ça devrait déjà réduire pas mal l’espace de recherche.

@elegance : le plus petit fait 3 cars. et le plus grand 42.

Concernant le if, je me suis trompé oui, j’avais corrigé, mais la vitesse est pareil.

@Bartpab : ce ne sera pas pratique pour l’avenir et ce n’est pas trop ce que je veux :P

@entwanne : je n’ai aucun mot qui dépasse les 42 cars. donc toutes les solutions sont possibles, car j’ai vraiment de toutes les longueurs, de 3 à 42.

  • Donc, je tire aléatoirement un élément du tableau et je l’efface via array_splice(); on l’appellera $a.
  • Ensuite, je retire tous les mots du tableau qui font ;(70 - strlen($a)); (ça je ne sais pas comment faire du coup)

@gasche : c’est plus ou moins ce que je fais, et c’est justement pour ça que c’est lent, cet "algo" n’est pas rapide

+0 -0

@entwanne : je n’ai aucun mot qui dépasse les 42 cars. donc toutes les solutions sont possibles, car j’ai vraiment de toutes les longueurs, de 3 à 42.

Machou

Non toutes les solutions ne sont pas possibles, ce n’est pas parce qu’un mot est conservé après la première étape qu’il le sera par la suite.

Si tu tires des mots de trois lettres pour les deux premiers, tous les mots de moins de quatorze lettres devraient être exclus à la 3ème étape.

@gasche : c’est plus ou moins ce que je fais, et c’est justement pour ça que c’est lent, cet "algo" n’est pas rapide

Ben non, ce n’est pas ce que fait le code que tu as montré plus haut — dont par ailleurs la condition pour recommencer est fausse, donc j’imagine que ce n’est pas le code que tu as écrit en pratique ? Est-ce que tu pourrais nous montrer ton vrai code ?

Tu fais plein de choses à moitié, mais rien complètement.

J’illustre :

  • Le code que tu as posté, il ressemble à celui que tu as vraiment mais ce n’est pas tout à fait le même code.

  • Je t’ai demandé : peux-tu nous dire combien tu as de mots de 5 lettres, combien de mots de 6 lettres, etc etc etc., et tu me réponds (à moi, nommément) : le plus petit fait 3 cars. et le plus grand 42.

Ce ne répond pas à ma question. Je pense que ma question était claire pourtant, non ?

La programmation, ça demande de la rigueur. Pas de rigueur, pas de résultat.

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte