8791 sujets

Développement web côté serveur, CMS

Pages :
Bonjour,

J'ai un petit soucis avec PHP. J'essai de créer un petit script permettant de mélanger des mots clés. Je m'explique, exemple un tableau :
- $tableau = array('bonjour', 'aurevoir', 'salut', 'test');

Je souhaiterais au final, obtenir un tableau qui aura mélanger toutes les valeurs du tableau entre elles, mais toujours seulement deux valeurs, comme ceci :
- $resultats = array('bonjour aurevoir', 'aurevoir bonjour', 'salut bonjour', 'salut aurevoir', 'test bonjour', etc...);

Savez-vous comment procéder pour réaliser ce petit script ?
Merci d'avance Smiley smile
Hop hop, voilà :


$arr = Array('bonjour', 'aurevoir', 'salut', 'test');

$result = Array();

foreach ($arr as $v)
{
	foreach ($arr as $v2)
	{
		if ($v !== $v2)
			$result[] = $v . ' ' . $v2;
	}
}

print_r($result);


Si tu as des questions ou si ça n'est pas ce que tu veux dis le moi.
Merci à chaque fois tu m'aides, c'est vraiment sympa ^^

Tu penses que ce serait possible de réaliser 'en casacade' ? C'est à dire mélanger tous les mots entre eux, mais sans s'arrêter à deux. D'aller jusque 3, 4 voir plus ... exemple "bonjour aurevoir salut" ; "bonjour salut aurevoir", 'bonjour salut aurevoir test', etc ...

Encore merci ^^
Modérateur
Ca lu,

Hummmm.... Il y a plus simple, plus rapide et voir optimisé : shuffle Smiley cligne

Pour faire simple et rapide :

$listeDonnees = Array('bonjour', 'aurevoir', 'salut', 'test'); 
shuffle($listeDonnees);
echo implode(" ",array_slice($listeDonnees, 0, 2));

Modifié par niuxe (25 Jul 2011 - 01:56)
Modérateur
jb_gfx a écrit :
Hop hop, voilà :


$arr = Array('bonjour', 'aurevoir', 'salut', 'test');

$result = Array();

foreach ($arr as $v)
{
	foreach ($arr as $v2)
	{
		if ($v !== $v2)
			$result[] = $v . ' ' . $v2;
	}
}

print_r($result);


Si tu as des questions ou si ça n'est pas ce que tu veux dis le moi.


Gaylord.P a écrit :

Merci à chaque fois tu m'aides, c'est vraiment sympa ^^

Tu penses que ce serait possible de réaliser 'en casacade' ? C'est à dire mélanger tous les mots entre eux, mais sans s'arrêter à deux. D'aller jusque 3, 4 voir plus ... exemple "bonjour aurevoir salut" ; "bonjour salut aurevoir", 'bonjour salut aurevoir test', etc ...

Encore merci ^^


Et l'eau,

Hier je n'avais pas trop le temps de répondre à ta belle ineptie. Si je comprends bien, si la problèmatique serait 5/10/20/50 mélanges sur X fois, tu ferais autant de boucles que le nombre demandé. Smiley biggol Smiley ravi

Donc pour finir cela en 2 lignes ! :

$listeDonnees = Array('bonjour', 'aurevoir', 'salut', 'test'); 
shuffle($listeDonnees);
$listeDonnees = array_fill(0,10,implode(" ",array_slice($listeDonnees, 0, 3)));
// ou (cela dépend de la suite)
// $listeDonneesFinale = array_fill(0,10,implode(" ",array_slice($listeDonnees, 0, 3)));
Tu as testé ton code au moins ? Parce que ça donne pas du tout le résultat qui est demandé ici (le but étant de construire toutes les phrases possibles avec les mots présent dans le tableau).

Sinon j'ai donné un exemple d'après l’énoncé du début. Mais pour faire des phrases avec 3, 4 ou plus de mots j'aurais écrit une fonction récursive.
Modifié par jb_gfx (26 Jul 2011 - 20:19)
Modérateur
jb_gfx a écrit :
Tu as testé ton code au moins ? Parce que ça donne pas du tout le résultat qui est demandé ici (le but étant de construire toutes les phrases possibles avec les mots présent dans le tableau).

Sinon j'ai donné un exemple d'après l’énoncé du début. Mais pour faire des phrases avec 3, 4 ou plus de mots j'aurais fait une fonction récursive.


J'avoue que la dernière ligne n'est pas tout à fait ce qui est demandé (erf, codage vite fait)... mais toujours en peu de lignes (là pour le coup 1 de plus) et pas besoin de fonction récursif ou truc plus indigeste à lire ! shuffle a bien sa place ! Si je comprends bien, tu rajoutes une boucle pour déterminer le nombre de string à insérer dans le tableau... Suivant ton code on serait à trois boucles injustifiées.

$listeDonnees = Array('bonjour', 'aurevoir', 'salut', 'test'); 
for($i = 0; $i < 10; $i++){ 
	shuffle($listeDonnees);
	$listeDonneesFinales[] = implode(" ",array_slice($listeDonnees, 0, 3));
}


Après, si un résultat a la même valeur qu'un précédent, il suffit d'implémanter une conditionnel ($i--) et si toutes les valeurs possibles sont dans le tableau finale (break) . Ce ne sera pas un code indigeste à lire, long, redondant et lourd (benchmark).

Après, le résultat sera le même de toute manière. Pour le coup, je t'offre une bière Smiley biere .
Tu fais fausse route, et ton résultat est encore faux. Shuffle comme son nom l'indique produit un résultat aléatoire ce qui n'est pas ce qu'on cherche ici.

Regarde ton tableau de résultats :

- Beaucoup de combinaisons manquent
- Beaucoup de combinaisons sont en doubles ou triples
- Les résultats sont aléatoires

PS : Quand tu veux pour la bière. Smiley cligne
Modifié par jb_gfx (26 Jul 2011 - 21:11)
Gaylord.P a écrit :
...
Tu penses que ce serait possible de réaliser 'en casacade' ? C'est à dire mélanger tous les mots entre eux, mais sans s'arrêter à deux. D'aller jusque 3, 4 voir plus ... exemple bonjour au revoir salut ; bonjour salut au revoir, bonjour salut aurevoir test, etc
...


Oui c'est possible »


<?php
 $br = '<br />';
 # -- 1 = index[0] et index[1] --
 $nombreIndex = 1; 
 # --
 $matrice = array('bonjour', utf8_decode('ça va ?'), 'merci', utf8_decode('à plus tard'), 'bonne fin de semaine', 'es-tu malade ?', 'je crois oui', 'sinon on verra');
 $phrase = '';
 # --
    for ($j = 0; $j <= $nombreIndex; $j++)
    {
    # --
       $aleatoire = array_rand($matrice);
       # --
       echo $br . 'Compteur ' . $j . ' => ' . $aleatoire . ' Appelle' . $br;
       echo '<xmp>';
         print_r($matrice) . $br;
       echo '</xmp>';
       # --
       $phrase .= $matrice[$aleatoire] . ' - ';
       # -- On supprime des index à chaque itération --
       unset($matrice[$aleatoire]);       
    }  
    # -- Affichage --
    echo $br . $br . utf8_decode('Générateur de phrases') . ' : ' . $br . $br . $phrase;
?>


Seuls les array sont en cascade : le générateur lui n'est pas en cascade. Mais c'est possible de faire en cascade avec le générateur de phrases.

Tu peux changer la valeur de $nombreIndex sans allez plus loin que la longeur de $matrice.
Si donc il y a 10 index : $nombreIndex pourra prendre la valeur entre 0 et 9;

» Tu veux joindre 2 phrases|mots : $nombreIndex = 1;
» Tu veux joindre 3 phrases|mots : $nombreIndex = 2;
» Tu veux joindre 5 phrases|mots : $nombreIndex = 4; etc.

Exemples de résultats »

$nombreIndex = 1 ) bonjour - ça va ?
$nombreIndex = 2 ) bonne fin de semaine - ça va ? - es-tu malade ?

Les données sont brut au navigateur : en 2 étapes distinctes.

1 ) print_r () avec <xmp> pour le formatage des arrays
2 ) générateur de phrases.

Tu remarqueras aussi que la valeur de $nombreIndex gère le nombre de array () avec des index en moins à chacun, puisque » unset ($matrice ($aleatoire)); agit à chaque itération.

Ne joue qu'avec la valeur de $nombreIndex pour voir correctement les changements.

Évidemment le script peut être modifier et ajuster pour plus de performances.

Script inspirer de : zenko » dont le but est de générer des password's à longeur variable.

J'ai voulu comprendre mieux, en étudiant le script et le présenter.
Si quelqu'un veut poursuivre, tant mieux. Ne reste plus qu'à utiliser l'effet de cascade sur le générateur de phrases.

Smiley smile

..
Modifié par zardoz (27 Jul 2011 - 01:08)
zardoz : ton résultat est complètement faux aussi.

1. Lisez l’énoncé.
2. La solution est la combinaison de deux algorithmes connus.
3. Google... (la solution se trouve en 2 minutes).
C'est possible j'ai pas vérifier.

Les résultats dans un array. Bon d'accord. Moi j'ai fait le choix d'un générateur de phrases. Les résultats du générateur ne sont pas dans un array. J'avoue. Je me suis livré à quelques fantaisies plutôt que de répondre à la question. Smiley biggrin

Il est toutefois difficile de gérer de belles phrases, ayant un sens précis avec un seul array et deux boucles foreach. Sauf évidemment si on intègre un élément fixe au tableau.

Dans l'exemple qui suit » un array une boucle foreach et un élément fixe.


<?php
$matrice1 = array('vous avez du feu', 'auriez-vous l\'heure ?', 'votre nom s.v.p');
$resultats = array();
foreach ($matrice1 as $mat1) {
  $resultats[] = 'Bonjour, ' . $mat1;
}
echo '<xmp>';
 print_r($resultats);
echo '</xmp>';
?>


Avec deux arrays » on pourra aussi contrôler la diversité, et la belle phrase »

Deux arrays, deux boucle foreach


<?php
$matrice1 = array ('Bonjour,', 'Salut,', 'Allo,', 'Bonsoir,', 'Dites-moi,'); 
$matrice2 = array('vous avez du feu ?', 'auriez-vous l\'heure ?', 'votre nom s.v.p');
$resultats = array();
foreach ($matrice1 as $mat1) {
 foreach ($matrice2 as $mat2)
  $resultats[] = $mat1 . ' ' . $mat2;
}
echo '<xmp>';
 print_r($resultats);
echo '</xmp>';
?>


Mais avec un seul array et deux boucles foreach il est simple de créer un nouveau array, mais plus difficile de contrôler la sigification logique des phrases.

C'est la faiblesse de ce genre de concaténation, plus difficile mais pas impossible.

..
Modifié par zardoz (27 Jul 2011 - 07:11)
Pour trouver toutes les combinaisons (power set) :

http://en.wikipedia.org/wiki/Power_set

Pour trouver toutes les permutations pour chaque combinaison :

http://en.wikipedia.org/wiki/Permutation

Une implémentation en PHP de ces 2 algos (Elle est pas de moi. Attention : le power set est rapide à calculer par contre les permutations sont lentes.) :


function cmp($a, $b)
{
    if ($a == $b) {
        return 0;
    }
    return ($a < $b) ? -1 : 1;
}

function power_perms($arr) {

    $power_set = power_set($arr);
    $result = array();
    foreach($power_set as $set) {
        $perms = perms($set);
        $result = array_merge($result,$perms);
    }
    return $result;
}

function power_set($in,$minLength = 1) {
   $count = count($in);
   $members = pow(2,$count);
   $return = array();
   for ($i = 0; $i < $members; $i++) {
      $b = sprintf("%0".$count."b",$i);
      $out = array();
      for ($j = 0; $j < $count; $j++) {
         if ($b{$j} == '1') $out[] = $in[$j];
      }
      if (count($out) >= $minLength) {
         $return[] = $out;
      }
   }
   usort($return,"cmp");  //can sort here by length
   return $return;
}

function factorial($int){
   if($int < 2) {
       return 1;
   }
   for($f = 2; $int-1 > 1; $f *= $int--);
   return $f;
}

function perm($arr, $nth = null) {

    if ($nth === null) {
        return perms($arr);
    }

    $result = array();
    $length = count($arr);

    while ($length--) {
        $f = factorial($length);
        $p = floor($nth / $f);
        $result[] = $arr[$p];
        array_delete_by_key($arr, $p);
        $nth -= $p * $f;
    }

    $result = array_merge($result,$arr);
    return $result;
}

function perms($arr) {
    $p = array();
    for ($i=0; $i < factorial(count($arr)); $i++) {
        $p[] = perm($arr, $i);
    }
    return $p;
}

function array_delete_by_key(&$array, $delete_key, $use_old_keys = FALSE) {
    unset($array[$delete_key]);

    if(!$use_old_keys) {
        $array = array_values($array);
    }

    return TRUE;
}

$data = Array('bonjour', 'aurevoir', 'salut', 'test');
$res = power_perms($data);

echo '<pre>';
foreach ($res as $v)
echo implode(' ', $v) . "\n";
echo '</pre>';

Modifié par jb_gfx (27 Jul 2011 - 12:04)
J'ai trouvé une implémentation beaucoup plus rapide dans le PHP Cook Book d'Oreilly.

Power set : http://docstore.mik.ua/orelly/webprog/pcook/ch04_25.htm
Permutation rapide : http://docstore.mik.ua/orelly/webprog/pcook/ch04_26.htm

Attention quand même : le calcul des permutations demande beaucoup de mémoire.

Et une fois adapté :


function cmp($a, $b)
{
    if ($a == $b) {
        return 0;
    }
    return ($a < $b) ? -1 : 1;
}

function pc_array_power_set($array)
{
	// initialize by adding the empty set
	$results = array(array( ));

	foreach ($array as $element)
		foreach ($results as $combination)
			array_push($results, array_merge(array($element), $combination));

	usort($results,"cmp");  //can sort here by length
	return $results;
}

function pc_next_permutation($p, $size) {
	// slide down the array looking for where we're smaller than the next guy
	for ($i = $size - 1; $i > -1 && $p[$i] >= $p[$i+1]; --$i) {}

	// if this doesn't occur, we've finished our permutations
	if ($i == -1) {
		return FALSE;
	}
	// the array is reversed: (1, 2, 3, 4) => (4, 3, 2, 1)
	// slide down the array looking for a bigger number than what we found before
	for ($j = $size; $p[$j] <= $p[$i]; --$j) {}
	// swap them
	$tmp = $p[$i];
	$p[$i] = $p[$j];
	$p[$j] = $tmp;
	// now reverse the elements in between by swapping the ends
	for (++$i, $j = $size; $i < $j; ++$i, --$j)
	{
		$tmp = $p[$i];
		$p[$i] = $p[$j];
		$p[$j] = $tmp;
	}
	return $p;
}

$data = Array('bonjour', 'aurevoir', 'salut', 'test');

// generate power set
$sets = pc_array_power_set($data);

echo '<h1>Power set</h1>';
foreach ($sets as $set)
{
	$size = count($set) - 1;
	if ($size > 0)
		echo implode(' ', $set) . '<br />';
}


// generate all permutations
foreach ($sets as $k => $set)
{
	$j = 0;
	$size = count($set) - 1;
	if ($size > 0)
	{
		$perm = range(0, $size);
		do {
			foreach ($perm as $i)
			{
				$perms[$k][$j][] = $set[$i];
			}
		} while ($perm = pc_next_permutation($perm, $size) and ++$j);
	}
}

echo '<h1>Permutations</h1>';
foreach ($perms as $perm)
	foreach ($perm as $p)
		echo implode(' ', $p) . '<br />';


Modifié par jb_gfx (27 Jul 2011 - 17:14)
Alors là c'est complet avec ces 2 algos. Mélanger les mots et la cascade.

Ça ne rendra pas plus facile la sortie naturel des phrases mais bon disons que ce n'est pas le rôle des algos que de donner un sens à la phrase.

Son rôle est pure mathématique, une façon d'utilisé complètement le array, une façon originale, sans rien négliger, sauf évidemment la réflexion avant la concaténation.

Disons que c'est valide, utile, dans différentes recherche de programmation. Pour des jeux ? , des moteurs de recherche ?, des Quiz ?

C'est sans limite je pense.

..
Il me semble que le but de Gaylord.P est de trouver toutes les combinaisons possibles de mots clés pour Adword (si j'ai bien suivi).
Alors les algos pourront bien lui servir. Ce genre de code c'est pour des buts très précis. Les mots clés, en est un exemple utile.

..
Bonjour à toutes et à tous,

@ gb_gfx : tu m'as fait une usine à gaz, pour quelque chose de simple. Smiley eek

De plus, la demande était de fournir dans un tableau des éléments contenant la concaténation combinatoire des chaines de caractères du tableau $data et non d'autres tableaux imbriqués. Voici la solution pourtant simple :
<?php
$data = Array('bonjour', 'au_revoir', 'salut', 'test'); 
$vide = Array();

function test($tab2, $tab1)
{
	$result = array();
	$size = count($tab2) - 1; 

	foreach ($tab1 as $elm1)
		if ($size > 0)
			foreach ($tab2 as $elm2)
			{
				if (strpos($elm2, $elm1) === false)
				{
					echo $elm1 . " - " . $elm2 . "<br/>";
					array_push($result, $elm1 . " - " . $elm2); 
				}
			}
		else
		{
			echo $elm1 . "<br/>";
			array_push($result, $elm1);
		}

	echo "--------------------------------<br />";

	return $result;
};

test(test(test(test(test($vide, $data), $data), $data), $data), $data);
?>
C'est nettement plus court ! Smiley cligne

Donc pour répondre à Gaylord.P, la solution consiste à faire en PHP :
$tableau = test($data, $data);
@+
Modifié par Artemus24 (27 Jul 2011 - 18:56)
Disons que le code que j'ai posté (qui est pas de moi, comme je l'ai précisé) à l'avantage d'être t utilisable en production sans gros changements (il faudrait un peu optimiser l'utilisation mémoire) et réutilisable. Ton code (bien inspiré de mon premier exemple) est une simple démo, je vois pas ce qu'on pourrait en faire dans un vrai projet.

Tu parles d'usine à gaz alors que ton exemple est le cas typique de ce qui fait les usines à gaz : code non réutilisable basé uniquement sur l'affichage et non sur le traitement des données. Je préfère largement de petites briques indépendantes les unes des autres et de l'affichage, qu'on peut appeler selon ses besoins et combiner entres elles qu'un script monolithique rigide et qui ne sert qu'à une seule tache.
Modifié par jb_gfx (27 Jul 2011 - 22:06)
Pages :