Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP] Generowanie listy z tablicy
Forum PHP.pl > Forum > Przedszkole
Kshyhoo
Nie wiem, jak nazwać to, co chciałbym osiągnąć. Mianowicie, chciałbym wygenerować listę kombinacji liczb i pominąć pewne formy ich powtórzeń. Może przykład powie więcej:
Kod
1    2    3    4
1    2    3    5
1    2    3    6
1    2    3    7
1    2    3    8
1    2    3    9
1    2    3    10
1    2    4    5
1    2    4    6
1    2    4    7
1    2    4    8
1    2    4    9
1    2    4    10
1    2    5    6
1    2    5    7
1    2    5    8
1    2    5    9
1    2    5    10
1    2    6    7
1    2    6    8
1    2    6    9
1    2    6    10
1    2    7    8
1    2    8    9
1    2    8    10
1    2    9    10
itd

czyli z zakresu liczb 1-10 wybieram 4. Chciałbym pominąć wystąpienie np. trzech i czterech liczb po sobie a także takich wystąpień jak co 2, co 3 (1, 3, 5, 7 albo 1, 4, 7, 10).
Jak do tego się zabrać? Lepiej wygenerować i potem usunąć to co mi nie pasuje, czy od razu pomijać?

Poradziłem sobie z generowaniem. Nie mogę jednak skumać, jak pozbyć się co niektórych wpisów, np:
1,2,3,4
1,3,5,7
1,2,4,5
Jakieś pomysły?
jaslanin
Napisz bardziej dokładnie o co Ci chodzi. Bo to co napisałeś jest niezbyt zrozumiałem

1.

czyli z zakresu liczb 1-10 wybieram 4.

Wybierasz na jakich zasadach (dlaczego akurat 4, to jest stała, losowa, jakoś liczona liczba?), i co z nimi robisz domyślałam się (szklana kula) że chodzi o 4 kolumny

2.

Chciałbym pominąć wystąpienie np. trzech i czterech liczb po sobie a także takich wystąpień jak co 2, co 3 (1, 3, 5, 7 albo 1, 4, 7, 10).

Wystąpień w kolumnach czy wierszach.

3. inne

dlaczego w pierwszej kolumnie są same jedynki, w drugiej same dwójki, w trzeciej w kolejności rosnącej, a w czwartej rosnąco do dziesięciu, a potem cykl się powtarza

Po prostu nie rozumie.
Kshyhoo
Eh. Przecież napisałem w miarę jasno:
1. tablica zawiera liczby (1,2,3,4,5,6,7,8,9,10) i generuję kombinację bez powtórzeń tych liczb, jak na przykładzie w pierwszym poście.
2. skoro kombinacja zawiera 4 liczby, to jasne, że są to wiersze.
3. skoro kombinacja jest w wierszu, wpierw pobierane są pierwsze liczby z tablicy (1,2,3,4), w drugim trzy pierwsze i kolejna (1,2,3,5), potem trzy pierwsze i następna (1,2,3,6), itd...

Jak już napisałem, sobie poradziłem z wygenerowaniem takiej kombinacji. Chciałbym teraz usunąć te, które mi nie odpowiadają, czyli np. wszystkie po sobie (1,2,3,4), (2,3,4,5), co druga (1,3,5,7), (2,4,6,8), co trzecia (1,4,7,10), również dwie, czy trzy w kupie (1,2,5,6), (1,2,3,8)
nospor
No dobra, a jak wygląda kod na generowanie i jak wygląda tablica wynikowa.

ps: skoro generujesz nie potrzebne dane, to już podczas generowania je wyrzucaj
Kshyhoo
Kod:
  1. $n=0;
  2. $ar1=array(1,2,3,4,5,6,7,8,9,10);
  3.  
  4. for( $l1=0, $size = count($ar1); $l1 <=$size-5; ++$l1) {
  5. for( $l2=$l1+1, $size = count($ar1); $l2 < $size-4; ++$l2) {
  6. for( $l3=$l2+1, $size = count($ar1); $l3 < $size-3; ++$l3) {
  7. for( $l4=$l3+1, $size = count($ar1); $l4 < $size-2; ++$l4) {
  8. for( $l5=$l4+1, $size = count($ar1); $l5 < $size-1; ++$l5) {
  9. for($l6=$l5+1, $size = count($ar1); $l6 < $size; ++$l6) {
  10.  
  11. //echo $n=$n+1;
  12. //echo ': ';
  13.  
  14. print $ar1[$l1].'|'.$ar1[$l2].'|'.$ar1[$l3].'|'.$ar1[$l4].'|'.$ar1[$l5].'|'.$ar1[$l6];
  15. print "<br>";
  16.  
  17. }
  18. }
  19. }
  20. }
  21. }
  22. }

Wynik działania (część):
1|2|3|4|5|6
1|2|3|4|5|7
1|2|3|4|5|8
1|2|3|4|5|9
1|2|3|4|5|10
1|2|3|4|6|7
1|2|3|4|6|8
1|2|3|4|6|9
1|2|3|4|6|10
1|2|3|4|7|8
1|2|3|4|7|9
1|2|3|4|7|10
1|2|3|4|8|9
1|2|3|4|8|10
1|2|3|4|9|10
1|2|3|5|6|7
1|2|3|5|6|8
1|2|3|5|6|9
1|2|3|5|6|10
nospor
  1. $n=0;
  2. $ar1=array(1,2,3,4,5,6,7,8,9,10);
  3.  
  4. for( $l1=0, $size = count($ar1); $l1 <=$size-5; ++$l1) {
  5. for( $l2=$l1+1, $size = count($ar1); $l2 < $size-4; ++$l2) {
  6. for( $l3=$l2+1, $size = count($ar1); $l3 < $size-3; ++$l3) {
  7. for( $l4=$l3+1, $size = count($ar1); $l4 < $size-2; ++$l4) {
  8. for( $l5=$l4+1, $size = count($ar1); $l5 < $size-1; ++$l5) {
  9. for($l6=$l5+1, $size = count($ar1); $l6 < $size; ++$l6) {
  10.  
  11. //echo $n=$n+1;
  12. //echo ': ';
  13. $data = array($ar1[$l1],$ar1[$l2],$ar1[$l3],$ar1[$l4],$ar1[$l5],$ar1[$l6]);
  14. if (test($data,1) || test($data,2))
  15. continue;
  16. print $ar1[$l1].'|'.$ar1[$l2].'|'.$ar1[$l3].'|'.$ar1[$l4].'|'.$ar1[$l5].'|'.$ar1[$l6];
  17. print "<br>";
  18. }
  19. }
  20. }
  21. }
  22. }
  23. }
  24.  
  25. function test($data, $diff){
  26. $i = 0;
  27. $c = count($data);
  28. $n = 0;
  29. for ($i=0; $i < $c-1;$i++){
  30. if ($data[$i+1] - $data[$i] == $diff)
  31. $n++;
  32. else
  33. $n = 0;
  34. if ($n>=2) return true; //bo chciałeś gdy 3 obok siebie to już wywalać
  35. }
  36.  
  37. return false;
  38. }
Kshyhoo
2, 3, 4, 5 obok siebie
co 2, 3, 4, 5...
Rozumiem, że mogę też tą funkcją wyszukiwać takie kombinacje z pliku? Bo mam zamiar przelecieć też to, co już wygenerowałem a potem zapisać ponownie w jednym pliku te, które są zgodne ze wzorcem a resztę w innym pliku.
nospor
Cytat
2, 3, 4, 5 obok siebie
co 2, 3, 4, 5...
Nie kumam o co ci teraz chodzi. Przecież ten kod pozbywa się właśnie wiersza 2,3,4,5. No przecież nie chciałeś liczb obok siebie.

Cytat
Rozumiem, że mogę też tą funkcją wyszukiwać takie kombinacje z pliku? Bo mam zamiar przelecieć też to, co już wygenerowałem a potem zapisać ponownie w jednym pliku te, które są zgodne ze wzorcem a resztę w innym pliku.
No funkcja przyjmuje tablicę. a skad ta tablica będzie to jej nie obchodzi. Równie dobrze może być z kosmosu - to twoja sprawa.
Kshyhoo
Już pisze o co chodzi.
- takie linie pomijam (albo zapisuję w pliku 1), bo jest 5 liczb obok siebie (podobnie, jeżeli jest 4, 3 lub 2):
1|2|3|4|5|6
1|2|3|4|5|7
1|2|3|4|5|8
1|2|3|4|5|9
1|2|3|4|5|10
- takie też, bo są pary, trójki:
1|2|5|7|8
1|2|3|8|9
- chciałbym usunąć też takie:
1|3|5|7|9
czyli co 2
1|4|7|10|13
czyli co 3
1|5|9|13|17
czyli co 4
...itd, do ostatniej liczby podanej w $ar1

I mam też pytanie: Wiem, że zwiększenie $ar1 ciągnie za sobą wzrost kombinacji, w przypadku $ar1=array(1,2,3,4,5,6,7,8,9,10); to:

$iloscKombinacji = (1 * 2 * 3 * 4 * 5 * 6) / (10 * 9 * 8 * 7 * 6 * 5);

Jak wyliczyć, ile kombinacji pominę, używając funkcji pomijania?
nospor
Cytat
- takie linie pomijam (albo zapisuję w pliku 1), bo jest 5 liczb obok siebie (podobnie, jeżeli jest 4, 3 lub 2):
1|2|3|4|5|6
1|2|3|4|5|7
1|2|3|4|5|8
1|2|3|4|5|9
1|2|3|4|5|10
- takie też, bo są pary, trójki:
1|2|5|7|8
1|2|3|8|9
- chciałbym usunąć też takie:
1|3|5|7|9
czyli co 2
1|4|7|10|13
czyli co 3
1|5|9|13|17
czyli co 4

No i to wszystko robi moja funkcja. Jedyne co musisz poprawic to to:
if ($n>=2) return true;
na
if ($n>=1) return true;
bo ty nawet pary chcesz usuwac

Cytat
Jak wyliczyć, ile kombinacji pominę, używając funkcji pomijania?
Sory, ale aż takim matematykiem nie jestem.

Na hama to zliczaj poprostu na bieżąco ile pominąłes i będziesz wiedział biggrin.gif
Kshyhoo
Plik wynikowy rośnie i mam problemy z otwarciem nawet po zwiększeniu pamięci. Wydaje mi się, że lepiej operować na pojedynczej linii z pliku. Można takie cuda w PHP?

EDIT. Chyba się udało:
  1. function test($data, $diff) {
  2. $i = 0;
  3. $c = count($data);
  4. $n = 0;
  5. for ($i=0; $i < $c-1;$i++) {
  6. if ($data[$i+1] - $data[$i] == $diff)
  7. $n++;
  8. else
  9. $n = 0;
  10. if ($n>=5) return true; //bo chciałeś gdy 3 obok siebie to już wywalać
  11. }
  12.  
  13. return false;
  14. }
  15. $n=0;
  16. $uchwyt = @fopen("plik.txt", "r");
  17. if ($uchwyt) {
  18. while (($bufor = fgets($uchwyt, 4096)) !== false) {
  19. $bufor = explode("|", $bufor);
  20. if (test($bufor,1) || test($bufor,2)) {
  21. continue;
  22. }
  23. echo $n=$n+1;
  24. echo ': ';
  25. echo'<pre>';
  26. print_r($bufor);
  27. echo'</pre>';
  28. }
  29. if (!feof($uchwyt)) {
  30. echo "Błąd: niespodziewany błąd fgets()\n";
  31. }
  32. fclose($uchwyt);
  33. }

Pobiera linia po linii i usuwa mi te, które są zgodne z wzorcem. teraz tylko zapis do plików (zgodne do jednego a niezgodne do drugiego).

No lipa, działa dobrze tylko powyżej 4 obok siebie - 3 i 2 obok siebie wycina wszystko. czyli przy warunku if ($n>=2) return true; powinno usuwać więcej niż 3 w kupie, czyli tak:

1,2,3,4,5,6
1,2,3,4,5,7
1,2,3,4,6,8
1,2,3,5,7,9

1,2,5,7,9,11

a jest:

1,2,3,4,5,6
1,2,3,4,5,7
1,2,3,4,6,8
1,2,3,5,7,9
1,2,5,7,9,11
nospor
Cytat
czyli tak:

1,2,3,4,5,6
1,2,3,4,5,7
1,2,3,4,6,8
1,2,3,5,7,9
1,2,5,7,9,11

a jest:

1,2,3,4,5,6
1,2,3,4,5,7
1,2,3,4,6,8
1,2,3,5,7,9
1,2,5,7,9,11
Pokazałeś dokładnie dwa takie same kwadraty, a z kontekstu wypowiedzi wynika, że powinny się różnić. W czym więc problem?
Kshyhoo
Nie powinno wyciąć linii na niebiesko a to robi.

Np:
  1. $uchwyt = @fopen("plik.txt", "r");
  2. if ($uchwyt) {
  3. while (($data = fgets($uchwyt, 4096)) !== false) {
  4. $data = explode(",", $data);
  5. if (test($data,1) || test($data,2)) {
  6. // DOBRE (czerwony)
  7. $data = implode(",", $data);
  8. echo '<font color="#f00">';
  9. echo $data.'</font><br>';
  10. continue;
  11. } else {
  12. // WYCIĘTE (niebieski)
  13. $data = implode(",", $data);
  14. echo'<font color="#00f">';
  15. echo $data.'</font><br>';
  16. continue;
  17. }
  18. }
  19. if (!feof($uchwyt)) {
  20. echo "Błąd: niespodziewany błąd fgets()\n";
  21. }
  22. fclose($uchwyt);
  23. }
nospor
Pokaz dokładnie jak na chwilę obecną wygląda funkcja test()
Kshyhoo
  1. function test($data, $diff) {
  2. $i = 0;
  3. $c = count($data);
  4. $n = 0;
  5. for ($i=0; $i < $c-1; $i++) {
  6. if ($data[$i+1] - $data[$i] == $diff)
  7. $n++;
  8. else
  9. $n = 0;
  10.  
  11. if ($n>=2) return true; // 3 obok siebie usuwa
  12.  
  13. }
  14.  
  15. return false;
  16. }
nospor
test($data,2)
No przecież badasz też dla różnicy DWA
A te dane:
1,2,5,7,9,11
spełaniają właśnie warunek dla różnicy DWA... no ksyhoooooooo mysl troche co piszesz tongue.gif
Kshyhoo
Odłożyłem ten skrypt na dwa tygodnie i nie mogę teraz skumać tej funkcji wink.gif Czyli linia:
  1. if (test($data,1) || test($data,2)) {

sprawdza, jak liczby stoją daleko od siebie?
A linia:
  1. if ($n>=2) return true;

w funkcji w takim razie?
nospor
Linia pierwsza co pokazałeś wywołuje funkcje test()...

Drugim argumentem funkcji test jest różnica jaką ma sprawdzać. Różnica między dwoma liczbami znajdującymi się obok siebie.
$n - liczb różnic (znajdujących sie obok siebie) pasujących do drugiego argumentu.
Kshyhoo
Czyli test($data,1) oznacza, że liczby są po kolei (1,2,3,4,5) a test($data,2), że co druga (1,3,5,7,9) - innymi słowy, sprawdza oddalenie liczb (np. co 2, co 3...)?

if ($n>=2) return true; a myślałem, że to sprawdza, ile liczb jest obok siebie (w tym wypadku 3)...
nospor
Cytat
Czyli test($data,1) oznacza, że liczby są po kolei (1,2,3,4,5) a test($data,2), że co druga (1,3,5,7,9) - innymi słowy, sprawdza oddalenie liczb (np. co 2, co 3...)?
Tak.

Cytat
if ($n>=2) return true; a myślałem, że to sprawdza, ile liczb jest obok siebie (w tym wypadku 3)...
Bo to właśnie robi, ale bierze pod uwagę różnicę. Dla różnicy 2, to liczby 1,3,5,7 są obok siebie. Dla różnicy 1 te libczy 1,3,5,7 nie są obok siebie. Dla różnicy 1 te liczby 1,2,3,4 są obok siebie.
Kshyhoo
No właśnie, przedobrzone wink.gif Bo powinno usunąć też przykład na niebiesko, czyli 2 liczby obok siebie - a nie robi tego, gdy wywołuje się funkcję kilka razy z innym parametrem.

Dodam, że dla warunku if ($n>=1) return true;
nospor
Cytat
No właśnie, przedobrzone
Było zrobione wg. twoich początkowych założeń. Jak nie chcesz sprawdzać dla różnicy DWA to ją poprostu wywal z tego warunku
if (test($data,1) || test($data,2))
Nikt ci tego nie broni.
Kshyhoo
Spoko, po prostu myślałem, że tylko rozróżnia kilka obok siebie a tu taka miła niespodzianka wink.gif Jeszcze raz dzięki za pomoc.

Mam jeszcze jeden problem: chciałbym zachować np. taką kombinację:
1,3,8,15,27,33
a takie usuwać:
1,3,5,8,15,27
czyli np. w rozstawie co 2 zachować pary a powyżej usuwać - analogicznie w rozstawie co 3, również zachować pary a usuwać powyżej, itp, dla 4, 5... 10.
nospor
Przeanalizuj wkoncu funkcje TEST(). Toż to pare linijek jest tylko.
No musisz ten warunek zmienic: if ($n>=1)
Kshyhoo
Sądzisz, że nie kombinowałem?
Zmieniałem w funkcji:
  1. if ($n>=1) return true; // 2 obok siebie usuwa
  2. if ($n>=2) return true; // 3 obok siebie usuwa
  3. if ($n>=3) return true; // 4 obok siebie usuwa
  4. if ($n>=4) return true; // 5 obok siebie usuwa
  5. if ($n>=5) return true; // 6 obok siebie usuwa

Grzebałem też tu:
  1. if ($data[$i+1] - $data[$i] == $diff)

żeby zmienić różnicę. Nawet zmieniałem to:
  1. if (test($data,1)) {

Żeby zmienić rozstawienie...
Bez efektu ;(
nospor
Cytat
if ($n>=1) return true; // 2 obok siebie usuwa
if ($n>=2) return true; // 3 obok siebie usuwa
if ($n>=3) return true; // 4 obok siebie usuwa
if ($n>=4) return true; // 5 obok siebie usuwa
if ($n>=5) return true; // 6 obok siebie usuwa
No i tak jest. To nie kumam jaki masz problem.
Kshyhoo
Bo usuwa wszystkie a ja chciałbym zachować pary w rozstawieniu...
nospor
Cytat
zachować pary w rozstawieniu...
Sorry ale nadal nie kumam co to znaczy.
Kshyhoo
Tu napisałem, ale powtórzę. Funkcja usuwa kombinacje np. co 2, czyli:
1,3,5,7,9,11
1,3,5,7,9,12
1,3,5,7,10,15
1,3,5,8,11,25
1,3,6,9,12,15
bo są liczby ulokowane co 2. Ja chciałbym zachować ostatni przykład, czyli pary (przypadek 1,3 albo 12,14) ... a już 3 usuwać (1,3,5 czy 12,14,16).
Nie mogę skumać, jaki warunek dać, żeby zostawiło takie kombinacje a usunęło inne.
Podobnie chcę zrobić z "trójkami", "czwórkami", ... czyli jak trafi 1,4,7,11,25 to usunie (bo różnica 3 ale 4 w kupie) a jak 2,8,15,17,25,33 to zostawi (bo różnica 3 ale tylko 2 w kupie).
Nie jestem "zawodowym" programistą a samoukiem, umiem generalnie to, co potrzebne do napisania strony www - jak przychodzi coś konkretniejszego, nie łapię tematu.
nospor
No to dodaj kolejny parametr do funkcji TEST() np. $nn i zamiast:
if ($n>=1)
rób
if ($n>=$nn)

A ten $nn bedziesz sam ustalał przy wywoływaniu funkcji TEST()
Kshyhoo
Też już pisałem, że tak kombinowałem i mi nie działało z założeniami. Nie wiem, co robię źle. Wkleję jak wrócę od medyka to, co udało mi się spłodzić.
nospor
Nie, nie pisałeś, że sparametryzowałeś $n
Kshyhoo
No właśnie nie wiem, jak zmienić to if ($n>=$2), bo generalnie działa. Jeżeli $n jest większa lub równa 2, to wykop... a nie wiem, jak zamienić to wykop na "jeżeli tylko będzie więcej niż jedna różnica".
No dobra, chyba działa:
  1. function test($data, $diff) {
  2. $i = 0;
  3. $c = count($data);
  4. $n = 0;
  5. for ($i=0; $i < $c-1; $i++) {
  6. if ($data[$i+1] - $data[$i] == $diff)
  7. $n++;
  8. else
  9. $n = 1; // <<<<<<<<< tu zmiana
  10. if ($n>=2) return true; // 3 obok siebie usuwa
  11. }
  12.  
  13. return false;
  14. }
  15.  
  16. // i w wywołaniu
  17. if (test($data,2)) {

Przykład:
1,3,5,7,9,11
1,3,5,7,9,12
1,3,5,7,10,15
1,3,5,8,12,18

1,3,8,15,21,33

niezgodne
zgodne
nospor
nie: $n>=$2
a: $n>=$nn
Przeciez pisałem....
A $nn to trzeci parametr funkcji test()
singollo
Przeczytałem cały wątek i nadal nie jestem pewien, czy dobrze rozumiem zadanie. Możecie mnie upewnić:

Dany jest zbiór uporządkowanych ciągów liczb. Należy z niego usunąć ciągi, które spełniają co najmniej jeden z poniższych warunków:
- zawierają N1 lub więcej liczb różniących się dokładnie o 1 (np. 1,2,3; 6,7,4; 9,10,11 itp). Długość takiego podciągu wynosi co najmniej N1.
- zawierają N2 lub więcej liczb różniących się dokładnie o 2 (np. 1,3,5; 2,4,6; itp). Długość takiego podciągu wynosi co najmniej N2.
- zawierają N3 lub więcej liczb różniących się dokładnie o 3 (np. 1,4,7; 2,5,8; itp). Długość takiego podciągu wynosi co najmniej N3.
....
- zawierają Nm lub więcej liczb różniących się dokładnie o m (np. 1,1+m,1+2m; 2,2+m,2+2m; itp). Długość takiego podciągu wynosi co najmniej Nm.

Dobrze zrozumiałem? Jeśli podacie wielkości N1, N2, ..., Nm to chyba będę w stanie zaproponować rozwiązanie...
Kshyhoo
Aaaaa, teraz kumam wink.gif Sprawdzę, jak wrócę od medyka a międzyczasie zobaczę, czy działa to, co ja spłodziłem (na przykładzie działa dobrze).

1. zakres liczb kombinacji (bez powtórzeń) 1-x (x może być np. 100, choć to da sporo kombinacji)
2. liczb w kombinacji 6 (1,2,3,4,5,6)
3. kombinacje liczb, gdzie wszystkie liczby są po kolei - WYKLUCZONE
4. kombinacje liczb, gdzie liczby są rozstawione co 2, 3, 4, 5, ..., n, WYKLUCZONE powyżej trzeciej (np. 1,5,7,9,11,18 usuwa ale 1,5,7,15,19,33 zostaje - bo 5 i 7 to 2 liczby)

to chyba na tyle...
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.