Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP]Jak niedopuścić do powtarzania liczby?
Forum PHP.pl > Forum > Przedszkole
thomson89
Witam!

Nie chcę aby liczby się powtarzały, jak to zrobić?

  1. $i = 0;
  2. while($i <= 16)
  3. {
  4. $liczba = rand(0, count($tabela));
  5. //inna czynność która musi być w tej pętli
  6. $i++;
  7. }
darko
  1. $i = 0;
  2. $temp = array();
  3. while($i <= 16)
  4. {
  5. while(!in_array($liczba = rand(0, count($tabela)), $temp)) {
  6. $temp[]=$liczba;
  7.  
  8. }
  9. //inna czynność która musi być w tej pętli
  10. $i++;
  11. }
  12. print_r($temp);
thomson89
Dzięki!
Fifi209
Problem w tamtym skrypcie jest taki, że gdy liczba jest w tablicy losuje kolejną i w końcowym wyniku nie będzie dokładnie tyle wylosowanych liczb ile zakłada programista.

To trzeba bardziej rozbudować, napisałem Ci coś takiego:
  1. <?php
  2.  
  3. $x = 1; // Przedział - od
  4. $y = 7; // Przedział - do
  5.  
  6. $z = 3; // Ilość liczb
  7.  
  8. function los(&$x, &$y, &$z) {
  9. static $v=0;
  10. static $arr=array();
  11.  
  12. if ($z != $v) {
  13. $l = rand($x, $y);
  14. if (!in_array($l, $arr)) {
  15. $arr[] = $l;
  16. $v++;
  17. }
  18.  
  19. los($x, $y, $z);
  20. }
  21.  
  22. return $arr;
  23. }
  24.  
  25. echo '<pre>';
  26. print_r(los($x, $y, $z));
  27.  
  28. ?>
darko
Fakt, update1:
  1. $i = 0;
  2. $temp = array();
  3. $przedzial = 16;
  4. $randomize = true;
  5. while($i <= $przedzial)
  6. {
  7. while($randomize) {
  8. if(!in_array($liczba = mt_rand(0, /*count($tabela)*/$przedzial), $temp)) {
  9. $temp[] = $liczba;
  10. $randomize = false;
  11. // ze względów "wydajnościowych" ;) dodaję poniższą linię kodu:
  12. unset($liczba);
  13. }
  14. }
  15. echo "i: ".$i." liczba: ".$liczba."<br/>";
  16. //inna czynność która musi być w tej pętli
  17. $i++;
  18. $randomize = true;
  19. }
  20. // ze względów "wydajnościowych" ;) dodaję poniższą linię kodu:
  21. unset($przedzial, $i, $temp, $randomize);
Fifi209
I uważasz, że takie zapętlanie jest dobre?
IMHO, takie zapętlanie jak pokazałeś będzie znacznie wolniejsze od mojej jednej funkcji. winksmiley.jpg
darko
IMHO "zapętlanie" będzie prawie zawsze mniej żerne od rekurencji i zmiennych statycznych winksmiley.jpg Poza tym - bez przesady - w tym przypadku nie ma sensu polemizować, co jest bardziej wydajniejsze. Po prostu dwa różne i działające rozwiązania tego samego problemu.
Fifi209
Zrobiłem dla Ciebie testy winksmiley.jpg

Oba skrypty w pętli for 100x

Twój: Czas sredni: 0.000751972198486

Mój: Czas sredni: 5.31625747681E-5 (0.0000531625747681)

Widzisz różnicę?
darko
Ok, zwracam honor, dzięki za teścik.
Hmm..
Ja też zrobiłem teścik w dwóch różnych skryptach, 100 losowanych liczb z przedziału 0-100:
Twój:
  1. $mtime = microtime();
  2. $mtime = explode(" ",$mtime);
  3. $mtime = $mtime[1] + $mtime[0];
  4. $starttime = $mtime;
  5. ////////////////////////////////////////
  6. $x = 0; // Przedział - od
  7. $y = 100; // Przedział - do
  8.  
  9. $z = 100; // Ilość liczb
  10.  
  11. function los(&$x, &$y, &$z) {
  12. static $v=0;
  13. static $arr=array();
  14.  
  15. if ($z != $v) {
  16. $l = rand($x, $y);
  17. if (!in_array($l, $arr)) {
  18. $arr[] = $l;
  19. $v++;
  20. }
  21.  
  22. los($x, $y, $z);
  23. }
  24.  
  25. return $arr;
  26. }
  27.  
  28. echo '<pre>';
  29. print_r(los($x, $y, $z));
  30.  
  31. ///////////////////////////////////////
  32. $mtime = microtime();
  33. $mtime = explode(" ",$mtime);
  34. $mtime = $mtime[1] + $mtime[0];
  35. $endtime = $mtime;
  36. $totaltime = ($endtime - $starttime);
  37. echo "This page was created in ".number_format($totaltime, 10)." seconds";

This page was created in 0.0198168755 seconds
a nawet:
This page was created in 0.0250329971 seconds

mój:
  1. $mtime = microtime();
  2. $mtime = explode(" ",$mtime);
  3. $mtime = $mtime[1] + $mtime[0];
  4. $starttime = $mtime;
  5. ////////////////////////////////////////
  6. $i = 0;
  7. $temp = array();
  8. $przedzial = 100;
  9. $randomize = true;
  10. while($i <= $przedzial)
  11. {
  12. while($randomize) {
  13. if(!in_array($liczba = mt_rand(0, /*count($tabela)*/$przedzial), $temp)) {
  14. $temp[] = $liczba;
  15. $randomize = false;
  16. // ze względów "wydajnościowych" ;) dodaję poniższą linię kodu:
  17. unset($liczba);
  18. }
  19. }
  20. echo "i: ".$i." liczba: ".$liczba."<br/>";
  21. //inna czynność która musi być w tej pętli
  22. $i++;
  23. $randomize = true;
  24. }
  25. // ze względów "wydajnościowych" ;) dodaję poniższą linię kodu:
  26. unset($przedzial, $i, $temp, $randomize);
  27. ///////////////////////////////////////
  28. $mtime = microtime();
  29. $mtime = explode(" ",$mtime);
  30. $mtime = $mtime[1] + $mtime[0];
  31. $endtime = $mtime;
  32. $totaltime = ($endtime - $starttime);
  33. echo "This page was created in ".number_format($totaltime, 10)." seconds";

This page was created in 0.0054590702 seconds
a nawet po którymś odświeżeniu strony wyszło
This page was created in 0.0044279099 seconds
Podtrzymuję zatem, swoje zdanie.
ps. podejrzewam, że gdybym jeszcze u siebie zakomentował linię 20. zamiast pluć echo w każdej iteracji i zamiast tego dałbym na samym końcu print_r($temp); wynik byłby jeszcze lepszy smile.gif Tak czy siak niech już ~thomson89 wybierze sobie bardziej optymalne rozwiązanie.
Fifi209
Twoje wyniki są co najmniej dziwne, wrzuć to do siebie:
  1. <?php
  2.  
  3.  
  4.  
  5. $times=array();
  6.  
  7. function los(&$x, &$y, &$z) {
  8. static $v=0;
  9. static $arr=array();
  10.  
  11. if ($z != $v) {
  12. $l = rand($x, $y);
  13. if (!in_array($l, $arr)) {
  14. $arr[] = $l;
  15. $v++;
  16. }
  17.  
  18. los($x, $y, $z);
  19. }
  20.  
  21. return $arr;
  22. }
  23.  
  24. $x = 1; // Przedział - od
  25. $y = 100; // Przedział - do
  26.  
  27. $z = 100; // Ilość liczb
  28.  
  29. for ($ix=0; $ix < 100; $ix++) {
  30. $start = array_sum(explode(" ",microtime()));
  31.  
  32. los($x, $y, $z);
  33.  
  34. $times[] = array_sum(explode(" ",microtime())) - $start;
  35. }
  36.  
  37. echo 'Czas sredni: '.(array_sum($times)/100).'<br/>';
  38.  
  39. $times=array();
  40.  
  41. $przedzial = 100;
  42. for ($ix=0; $ix < 100; $ix++) {
  43. $start = array_sum(explode(" ",microtime()));
  44. $i = 0;
  45. $temp = array();
  46. $randomize = true;
  47.  
  48. while($i <= $przedzial)
  49. {
  50. while($randomize) {
  51. if(!in_array($liczba = mt_rand(0, /*count($tabela)*/$przedzial), $temp)) {
  52. $temp[] = $liczba;
  53. $randomize = false;
  54. // ze względów "wydajnościowych" ;) dodaję poniższą linię kodu:
  55. unset($liczba);
  56. }
  57. }
  58. // echo "i: ".$i." liczba: ".$liczba."<br/>";
  59. //inna czynność która musi być w tej pętli
  60. $i++;
  61. $randomize = true;
  62. }
  63.  
  64. $times[] = array_sum(explode(" ",microtime())) - $start;
  65. }
  66.  
  67. echo 'Czas sredni: '.(array_sum($times)/100).'<br/>';
  68.  
  69.  
  70. ?>


I zobaczysz, co działa szybciej. Dodam, że zakodowałem u Ciebie echo i u mnie również usunąłem wyświetlanie.
darko
Faktycznie, najwyraźniej muszę się nauczyć robić testy wydajnościowe.
Wicepsik
  1. $i=0;
  2. $liczby = array();
  3. for ($ix=0; $ix < 100; $ix++) {
  4. $start = array_sum(explode(" ",microtime()));
  5.  
  6. do{
  7. if(!in_array($liczba = mt_rand(0, 100), $liczby)){
  8. $liczby[] = $liczba;
  9. $i++;
  10. }
  11. }while($i<100);
  12.  
  13. $times[] = array_sum(explode(" ",microtime())) - $start;
  14. }
  15. echo 'Czas sredni: ';
  16. printf("%.10f", (array_sum($times)/100));


Czas sredni: 0.000356862545013 Fifi
Czas sredni: 0.00377001523972 darko
Czas sredni: 0.0000154257 mój
Fifi209
Cytat(Wicepsik @ 21.02.2010, 14:36:38 ) *
  1. $liczby = array();
  2. for ($ix=0; $ix < 100; $ix++) {
  3. $start = array_sum(explode(" ",microtime()));
  4.  
  5. do{
  6. if(!in_array($liczba = mt_rand(0, 100), $liczby)){
  7. $liczby[] = $liczba;
  8. }
  9. }while($i<100);
  10.  
  11. $times[] = array_sum(explode(" ",microtime())) - $start;
  12. }
  13. echo 'Czas sredni: ';
  14. printf("%.10f", (array_sum($times)/100));


Czas sredni: 0.000356862545013 Fifi
Czas sredni: 0.00377001523972 darko
Czas sredni: 0.0000154257 mój


Jak Twój ma działać, skoro nie zwiększasz licznika $i w pętli? Poza tym, gdy już liczba istnieje ma losować kolejną tak długo, aż wylosuje unikalną.
Wicepsik
Racja. Poprawiłem już skrypt. Czas przy 10tys powtórzeń: 0.00002792100906
darko
~Wicepsik Twój skrypt - podobnie, jak moje pierwsze rozwiązanie - generuje tablicę o różnej ilości elementów, raz jest 100, innym razem 101 elementów. Sprawdź.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.