Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Zaawansowane sortowanie tabel
Forum PHP.pl > Forum > PHP
markonix
Swego czasu udało mi się stworzyć zapytanie SQL, które bez PHP tworzyło mi ładną tabelę sezonu (tabela ligowa - piłka nożna) z punktami, strzelonymi bramkami itp.
Niestety posortowanie wg punktów nie zawsze zdaje zadanie bo przy remisie punktowych w grę zaczynają już wchodzić dość skomplikowane algorytmy.

Przykładowo przy remisie brane są pod uwagę punkty zdobyte w meczach między remisującymi drużynami. Na pewno już tego nie dam rady czystym SQL ogarnąć dlatego już zrobię to w PHP.
Jednak to też nie jest jakieś super łatwe bo zastanawiam się jak potem to i tak posortować.

Infantylnie by było dodać jako indeks liczbę punktów, a potem ułamkowo dodać liczbę tych punktów.

Te rozwiązanie pomijam więc przychodzą mi tylko dwie opcje:

Sortowanie po kolejnych atrybutach.

Drużyna A:
- punktów 10
- punktów między drużynami co mają 10 - 9
- inne atrybuty (nazwa itp).

Drużyna B
- punktów 10
- punktów między drużynami co mają 10 - 7
- inne atrybuty (nazwa itp).

I podobny pomysł tylko użyciu multiarray:

$table[liczba_punktow][liczba_punktow_miedzy_remisujacymi][kolejne_warunki_s
ortujace]

Sortuje najpierw po liczbie punktów, potem po drugiej liczbie, potem po bilansie bramkowym itp.

Jakieś sugestie i potem narzędzia aby to potem posortować bo tak wielu atrybutach/kluczach?
SmokAnalog
Jeśli wszystko masz w bazie, to pokusiłbym się najpierw o próbę posortowania w czystym SQL smile.gif
markonix
Może troszkę źle sprecyzowałem - w bazie mam tylko MECZE, i mam już blisko 100 linijkowy SQL, który liczy punkty i inne wartości do tabeli za pomocą CASE (jeżeli wygrana to 2 punkty, 1 remis itp).
Potem troszkę grupowania i sortowania no ale na tym koniec. Nie widzę opcji (przy moich umiejętnościach) aby w tym samym SQL dodać jeszcze liczenie tych warunków przy remisie punktowym.
SmokAnalog
Ja nie znam tych kryteriów sortowania, ale na ten moment mogę podpowiedzieć tyle (nie jestem pewien czy to wiesz), że od takich sortowań jest funkcja usort. Jeśli będziesz sortował liczby malejąco, to coś w tym stylu będzie:
  1. usort($tablica, function ($a, $b) {
  2. $wynikA = // skomplikowane operacje na $a;
  3. $wynikB = // skomplikowane operacje na $b
  4. return $wynikB - $wynikA;
  5. });

Ale pewnie to wiesz jak dajesz radę ze skomplikowanym SQL-em.
markonix
Z funkcji nigdy nie korzystałem ale jest dobrym punktem zaczepienia.

Generalnie robię na razie tak:

1. Generuje normalne wyniki tabeli.
2. Obracam pętle i sprawdzam czy są jakieś remisy punktowe.
3. Remisy punktowe przekazuje do funkcji podobnej jak w kroku pierwszym czyli zapytanie SQL które jednak liczy punkty tylko dla wskazanych drużyn i tylko punkty.
4. Punkty zdobyte w tej podgrupie przypisuje do obiektu np. points_2.

No i mamy tablicę z obiektami, którą trzeba posortować.

Jeżeli mamy wynik z bazy w tablicach to jest gotowiec tutaj:
http://php.net/manual/en/function.array-multisort.php#100534

Ja akurat mam to na obiektach ale nie musiałem powyższej edytować bo znalazłem analogiczną funkcję tutaj:
http://blog.amnuts.com/2011/04/08/sorting-...comment-page-1/

Nie zmienia to faktu, że generowanie tej tabeli mocno się komplikuje i generuje troszkę zapytań ale najwyżej się pomyśli o jakimś cache..

Na razie zrobiłem tylko jedno rozwiązanie remisu, bo w tych drugich punktach też może być remis wtedy liczy się co innego i tak jest aż 5! różnych sytuacji, a 6 (wg specyfikacji) to losowanie przez włodarzy biggrin.gif
SmokAnalog
Jeśli to jest aż tak skomplikowane, to najlepiej krok po kroku i w którymkolwiek momencie przewagi którejkolwiek z drużyn od razu zwrócić wartość mniejszą od 0, gdy A będzie wyżej i większą od 0 dla przewagi B. przypadku remisu na każdym etapie, nie zwracasz jeszcze nic. W ten sposób kod będzie całkiem ładny smile.gif

Przykład:
  1. usort($tablica, function ($a, $b) {
  2. // pierwszy etap, liczysz sobie $wynikA i $wynikB
  3. if ($wynikA !== $wynikB) {
  4. return $wynikB - $wynikA;
  5. }
  6.  
  7. // drugi etap, liczysz sobie $wynikA i $wynikB
  8. if ($wynikA !== $wynikB) {
  9. return $wynikB - $wynikA;
  10. }
  11.  
  12. // itd.
  13.  
  14. return 0; // <== remis totalny, nie ingerujesz w kolejność, chociaż to pewnie nie ma prawa się wydarzyć w tabeli sportowej, no ale elegancko dać na końcu return 0
  15. });

Tym sposobem każdy etap liczysz sobie oddzielnie, nie musisz się przejmować poprzednim, przez co łatwiej będzie ogarnąć kod. Przykładowo, na etapie drugim wiesz już, że poprzednio był remis, więc zajmujesz się tylko logiką tego drugiego etapu.
markonix
Też ładny sposób jednak samo sortowanie u mnie nie wygląda specjalnie źle:

  1. osort($league_table, array('points' => SORT_DESC, 'same_points' => SORT_DESC, 'kolejna_wartosc' => SORT_DESC));


wink.gif

Bardziej chodzi o uzupełnienie obiektów w tablicy o te 'same_points', 'kolejna_wartosc' bo do ich policzenia potrzebuje dość specyficznych zapytań/pętli wink.gif
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.