Générer des nombres aléatoires différents des précédents

b3n
Petit nouveau ! | 2 Messages

11 oct. 2010, 15:31

Bonjour à tous,

J'essaie de générer des séries de nombres aléatoires compris dans un certain intervalle. Jusque là, rien de compliqué.
Il faut que j'applique une condition aux nombres générés : il doivent être différents des précédents.

Par exemple (5 nombres compris entre 1 et 50, différents entre eux):

7 - 45 - 21 - 20 - 38 -> bon
12 - 19 - 45 - 12 - 39 -> pas bon

J'ai essayé comme ceci (mais je ne teste la valeur qu'une fois et génère un nouveau nombre le cas échéant; il faudrait générer un nombre jusqu'à en obtenir un qui n'est pas encore dans notre tableau) :
<?php

$suite = array();

for ($i = 1; $i <= 5; $i++)
{
  $number = mt_rand(1, 50);

  if (in_array($number, $suite))
  {
    $newNumber = mt_rand(1, 50);

    if ($newNumber == $number)
    {
      $number = mt_rand(1, 50);
    }
    
    $number = $newNumber;
  }

  $suite[$i] = $number;
  echo "$number <br/>\n";
}
Auriez-vous une idée de solution ?

Merci d'avance.
Modifié en dernier par b3n le 11 oct. 2010, 15:39, modifié 1 fois.

ViPHP
xTG
ViPHP | 7331 Messages

11 oct. 2010, 15:37

$nb_a_tirer = 5;
$val_min = 1;
$val_max = 50;
$tab_result = array();
while($nb_a_tirer != 0 )
{
  $nombre = mt_rand($val_min, $val_max);
  if( !in_array($nombre, $tab_result) )
  {
    $tab_result[] = $nombre;
    $nb_a_tirer--;
  }
}
Ceci devrait faire ce que tu souhaites. :)

ViPHP
ViPHP | 5462 Messages

11 oct. 2010, 15:38

faut faire une fonction récursive :wink:

EDIT : non oublie celle de xTG est top
Modifié en dernier par stealth35 le 11 oct. 2010, 15:55, modifié 1 fois.

b3n
Petit nouveau ! | 2 Messages

11 oct. 2010, 15:55

Salut xTG, ça fonctionne impec', un grand merci :P

Eléphant du PHP | 422 Messages

12 oct. 2010, 13:35

hello

il y a la possibilité de faire un tableau avec les chiffres dans l'ordre puis de d'utiliser shuffle() et de dépiller à chaque fois que l'on prend une valeur
évite de faire des test in_array()
Modifié en dernier par telnes le 12 oct. 2010, 14:09, modifié 1 fois.
toujours faire une recherche sur http://www.php.net et/ou sur http://www.google.fr :)
utiliser http://ideone.com/ pour vos codes :)

ViPHP
xTG
ViPHP | 7331 Messages

12 oct. 2010, 13:39

Du fait que in_array() parcourt le tableau dans sa totalité ?

Cela revient au même que ta méthode impliquant le fait de construire le tableau et donc de faire une boucle sur 50 éléments (c'est même pire que ce que j'ai proposé car j'ai moins d'itérations - dans le meilleur des cas - ). De plus tu crois que shuffle fonctionne comment ? Je ne pense pas qu'il puisse reconstruire un tableau sans parcourir la source avant. (donc des itérations supplémentaires)

Eléphant du PHP | 422 Messages

12 oct. 2010, 14:50

pour en avoir le coeur net un petit Bench :)
<?php
set_time_limit(0);


$nb_iterration = 1;
$size = 60;


function MakeRandomNumShuffle($size){
	
	$tab_result = range(1,$size);
	shuffle($tab_result);
	return $tab_result;
}

function MakeRandomNumWhile($size){
	$nb_a_tirer = $size;
	$val_min = 1;
	$val_max = $size+100; // +100 = pour éviter de mouliner 
	$tab_result = array();
	while($nb_a_tirer != 0 )
	{
	  $nombre = mt_rand($val_min, $val_max);
	  if( !in_array($nombre, $tab_result) )
	  {
	    $tab_result[] = $nombre;
	    $nb_a_tirer--;
	  }
	} 
 	
 	return $tab_result;
}
//-----------------------------
$time_startA = microtime(true);
ob_start();

for($i=0;$i<$nb_iterration;$i++){
 
 	MakeRandomNumWhile($size);
 
}
$time_endA = microtime(true);
//-----------------------------

$time_startB = microtime(true);
ob_start();

for($i=0;$i<$nb_iterration;$i++){
 
 	MakeRandomNumShuffle($size);
 
}
$time_endB = microtime(true);
//-----------------------------


$timeA = $time_endA - $time_startA;
$timeB = $time_endB - $time_startB;
$div = $timeA/$timeB;


echo "While size $size ; $nb_iterration fois : $timeA  seconds<br/>\n";
echo "shuffle size $size ; $nb_iterration fois : $timeB  seconds<br/>\n";
echo "while/shuffle $div<br/>\n";
?>
résultat :

While size 10 ; 5 fois : 0.00015497207641602 seconds
shuffle size 10 ; 5 fois : 4.3153762817383E-005 seconds
while/shuffle 3.5911602209945

While size 20 ; 5 fois : 0.00033688545227051 seconds
shuffle size 20 ; 5 fois : 6.5088272094727E-005 seconds
while/shuffle 5.1758241758242

While size 40 ; 5 fois : 0.00076580047607422 seconds
shuffle size 40 ; 5 fois : 0.00010299682617188 seconds
while/shuffle 7.4351851851852

While size 60 ; 5 fois : 0.0018417835235596 seconds
shuffle size 60 ; 5 fois : 0.00014591217041016 seconds
while/shuffle 12.622549019608

de manière générale utiliser les fonctions native est plus rapide. Mais j'ai pu faire une erreur !

++
toujours faire une recherche sur http://www.php.net et/ou sur http://www.google.fr :)
utiliser http://ideone.com/ pour vos codes :)

ViPHP
ViPHP | 5462 Messages

12 oct. 2010, 15:21

si tu veux faire une liste de 5 nombres entre 0 et 1 milliard avec le suffle ca va prendre de la ressource

Eléphant du PHP | 422 Messages

12 oct. 2010, 15:28

... j'avais pas demandé un Billard , j'avais demandé un Milliard

et moi

tu crois que j'avais demandé une grosse Mite

:mrgreen:
pour 1 milliards le PC il plante ...
toujours faire une recherche sur http://www.php.net et/ou sur http://www.google.fr :)
utiliser http://ideone.com/ pour vos codes :)

ViPHP
ViPHP | 5462 Messages

12 oct. 2010, 15:31

... j'avais pas demandé un Billard , j'avais demandé un Milliard

et moi

tu crois que j'avais demandé une grosse Mite

:mrgreen:
pour 1 milliards le PC il plante ...
alors qu'avec celle d'xTG ca marche
$nb_a_tirer = 5;
$val_min    = 0;
$val_max    = PHP_INT_MAX;
$tab_result = array();

while($nb_a_tirer)
{
    $nombre = mt_rand($val_min, $val_max);
    if(!in_array($nombre, $tab_result))
    {
        $tab_result[] = $nombre;
        --$nb_a_tirer;
    }
}

var_dump($tab_result);

Eléphant du PHP | 422 Messages

12 oct. 2010, 15:50

bas met $nb_a_tirer = PHP_INT_MAX;
toujours faire une recherche sur http://www.php.net et/ou sur http://www.google.fr :)
utiliser http://ideone.com/ pour vos codes :)

ViPHP
ViPHP | 5462 Messages

12 oct. 2010, 15:54

bas met $nb_a_tirer = PHP_INT_MAX;
c'est pas le but du topic, avec suffle la liste sera aussi grande le nombre de valeur entre $val_min et $val_max
a moins de faire un array_slice apres mais avec de grandes valeurs c'est pas possible

Eléphant du PHP | 422 Messages

12 oct. 2010, 16:19

de toute façon il y a deux paramètres
  • la taille du tableau de valeur aléatoire unique
    le gap entre min et max
la dessus on gère pas de la même manière si c'est pour des grands ou des petits nombres.

je proposais une autre alternative tout simplement, qui fonctionne bien pour les petits nombre genre 5 nombre entre 1 et 50 !

++
toujours faire une recherche sur http://www.php.net et/ou sur http://www.google.fr :)
utiliser http://ideone.com/ pour vos codes :)

ViPHP
ViPHP | 5462 Messages

12 oct. 2010, 16:21

de toute façon il y a deux paramètres
  • la taille du tableau de valeur aléatoire unique
    le gap entre min et max
la dessus on gère pas de la même manière si c'est pour des grands ou des petits nombres.

je proposais une autre alternative tout simplement, qui fonctionne bien pour les petits nombre genre 5 nombre entre 1 et 50 !

++
ok montre moi ton code qui fait : 5 nombres entre 1 et 50 avec suffle

Eléphant du PHP | 422 Messages

12 oct. 2010, 16:34

a bas j' en ai fait un autre
function MakeRandomNumIsset($size,$min,$max){
	
	$tab = array();
	while(count($tab) != $size){
	 	$v = rand($min,$max);
	 	if(!isset($tab[$v])){
	 		$tab[$v] = $v;
	 	}
	}

	return $tab;
}
isset() est plus rapide que in_array()

Note : dans le cas ou on veux 50 chiffres aléatoires parmi 1 à 50 faire un truc du genre
$tab_result = range($min,$max);
shuffle($tab_result);

est plus rapide (toute proportion gardé sur la taille du tableau )

apres si il en faut juste 5
$tab_result = array_chunk($tab_result,5); // ou for ??
Modifié en dernier par telnes le 12 oct. 2010, 16:47, modifié 2 fois.
toujours faire une recherche sur http://www.php.net et/ou sur http://www.google.fr :)
utiliser http://ideone.com/ pour vos codes :)