Sort πίνακα βάσει τιμής σε υπο-πίνακα

Σε αυτή την περιοχή μπορείτε να βρείτε ή να αναζητήσετε πληροφορίες σχετικές με την PHP

Συντονιστές: WebDev Moderators, Super-Moderators, PHP Moderators

Απάντηση
Άβαταρ μέλους
philos
Δημοσιεύσεις: 264
Εγγραφή: 30 Αύγ 2007 23:32

Sort πίνακα βάσει τιμής σε υπο-πίνακα

Δημοσίευση από philos » 21 Ιούλ 2014 22:59

Καλησπέρα!
Έχω το εξής ερώτημα: έχουμε τον ακόλουθο πίνακα που έχει διαμορφωθεί σε php (σαν δίνω παράδειγμα από var_dump):

Κώδικας: Επιλογή όλων

array (size=X)
  22 => 
    array (size=Χ)
      'forumid' => string '22' (length=2)
      'lastpost' => string '0' (length=1)
  73 => 
    array (size=Χ)
      'forumid' => string '73' (length=2)
      'lastpost' => string '1394563443' (length=10)
  98 => 
    array (size=X)
      'forumid' => string '98' (length=2)
      'lastpost' => string '1404846768' (length=10)
  117 => 
    array (size=X)
      'forumid' => string '117' (length=3)
      'lastpost' => string '1393869412' (length=10)
[...]
Θέλω να κάνω sort αυτόν τον πίνακα βάσει της τιμής lastpost, είτε DESC είτε ASC.
Δηλαδή, αν γίνει με DESC, να επιστραφεί ο πίνακας:

Κώδικας: Επιλογή όλων

array (size=X)
  98 => 
    array (size=X)
      'forumid' => string '98' (length=2)
      'lastpost' => string '1404846768' (length=10)
  73 => 
    array (size=Χ)
      'forumid' => string '73' (length=2)
      'lastpost' => string '1394563443' (length=10)
  117 => 
    array (size=X)
      'forumid' => string '117' (length=3)
      'lastpost' => string '1393869412' (length=10)
  22 => 
    array (size=Χ)
      'forumid' => string '22' (length=2)
      'lastpost' => string '0' (length=1)
[...]
Πως μπορώ να το κάνω αυτό; Έχω βρει function που κάνει sort by value, όμως εδώ μιλάμε για πίνακες μέσα σε πίνακα.

Σας ευχαριστώ :D

Άβαταρ μέλους
fafos
Script Master
Δημοσιεύσεις: 6235
Εγγραφή: 30 Νοέμ 2004 03:09

Sort πίνακα βάσει τιμής σε υπο-πίνακα

Δημοσίευση από fafos » 21 Ιούλ 2014 23:30

Κώδικας: Επιλογή όλων

$lastpost = array();
foreach ($array as $k => $v)
{
    $lastpost[$k] = $v['lastpost'];
}
array_multisort($lastpost, SORT_DESC, $array);
Οι πάνες και οι πολιτικοί πρέπει να αλλάζονται συχνά για τον ίδιο λόγο...

Άβαταρ μέλους
dva_dev
Script Master
Δημοσιεύσεις: 3790
Εγγραφή: 16 Σεπ 2005 01:32
Επικοινωνία:

Sort πίνακα βάσει τιμής σε υπο-πίνακα

Δημοσίευση από dva_dev » 21 Ιούλ 2014 23:31

Για δοκίμασε με τη uasort κάπως έτσι:

Κώδικας: Επιλογή όλων

uasort($array, 'cmp');

function cmp($a, $b) {
    if ($a['lastpost'] == $b['lastpost']) {
        return 0;
    }
    return ($a['lastpost'] > $b['lastpost']) ? -1 : 1;
}

Άβαταρ μέλους
burnmind
Script Master
Δημοσιεύσεις: 954
Εγγραφή: 26 Σεπ 2009 02:14
Τοποθεσία: UK
Επικοινωνία:

Sort πίνακα βάσει τιμής σε υπο-πίνακα

Δημοσίευση από burnmind » 21 Ιούλ 2014 23:40

Και μία εναλλακτική (για version 5.3 και άνω) που είχα δει κάποτε και μου άρεσε πολύ (από εδώ αν θυμάμαι καλά):

Κώδικας: Επιλογή όλων

uasort($array, function($a, $b) {
    return $a['lastpost'] - $b['lastpost'];
});

Άβαταρ μέλους
philos
Δημοσιεύσεις: 264
Εγγραφή: 30 Αύγ 2007 23:32

Sort πίνακα βάσει τιμής σε υπο-πίνακα

Δημοσίευση από philos » 22 Ιούλ 2014 22:55

Ευχαριστώ παιδιά, δούλεψε κανονικά :)

Και κάτι άλλο, μιας που βρήκα ότι με δυσκολεύουν κι άλλα:

Έχουμε τον παραδειγματικό πίνακα που σας παρέθεσα στο αρχικό post (σας δίνω και το κλειδί parentid και title):

Κώδικας: Επιλογή όλων

array (size=X)
  73 =>
    array (size=Χ)
      'title' => string 'HEADER CAT1'
      'forumid' => string '73' (length=2)
      'lastpost' => string '0' (length=10)
      'parentid' => string '-1' (length=1)
  118 =>
    array (size=X)
      'title' => string 'Tralalala'
      'forumid' => string '118' (length=3)
      'lastpost' => string '1393869452' (length=10)
      'parentid' => string '73' (length=2)
  98 =>
    array (size=X)
      'title' => string 'HEADER CAT2'
      'forumid' => string '98' (length=2)
      'lastpost' => string '0' (length=10)
      'parentid' => string '-1' (length=1)
  22 =>
    array (size=Χ)
      'title' => string 'My name is George'
      'forumid' => string '22' (length=2)
      'lastpost' => string '1404846768' (length=1)
      'parentid' => string '98' (length=2)
  117 =>
    array (size=X)
      'title' => string 'I love pets'
      'forumid' => string '117' (length=3)
      'lastpost' => string '1393869412' (length=10)
      'parentid' => string '98' (length=2)
  217 =>
    array (size=X)
      'title' => string 'I love electronics'
      'forumid' => string '217' (length=3)
      'lastpost' => string '1393839412' (length=10)
      'parentid' => string '98' (length=2)
[...]
Αυτό μας δίνει τη λίστα forum (προτού κάνουμε οποιοδήποτε sort by lastpost) :

Κώδικας: Επιλογή όλων

- HEADER CAT1 (= έχει parentid -1)
-- Tralalala
- HEADER CAT2 (= έχει parentid -1)
-- My name is George
-- I love pets
-- I love electronics
Θέλω λοιπόν να κάνω sort τον πίνακα με βάσει την τιμή lastpost, αλλά μόνο μεταξύ των forums ενός Header Cat (parentid -1).
Πχ αν κάποιος κάνει post στο I love electronics, η τιμή lastpost θα ενημερωθεί, οπότε θέλουμε το forum I love electronics να πάει στην κορυφή, έτσι η λίστα θα γίνει:

Κώδικας: Επιλογή όλων

- HEADER CAT1 (= έχει parentid -1)
-- Tralalala
- HEADER CAT2 (= έχει parentid -1)
-- I love electronics
-- My name is George
-- I love pets
.. το ίδιο θέλουμε να γίνεται και με τα όποια forums έχει κάποιος άλλος Header.

Πως μπορώ λοιπόν να κάνω σωστά sort τον πίνακα;

Μένει άλλο ένα ερωτηματάκι, αλλά θα το θέσω μόλις βρούμε λύση για το παραπάνω. :D

Άβαταρ μέλους
burnmind
Script Master
Δημοσιεύσεις: 954
Εγγραφή: 26 Σεπ 2009 02:14
Τοποθεσία: UK
Επικοινωνία:

Sort πίνακα βάσει τιμής σε υπο-πίνακα

Δημοσίευση από burnmind » 23 Ιούλ 2014 15:18

Γιατί προσπαθείς να τα κάνεις όλα αυτά με πολύπλοκα sorting functions στην PHP και δε φέρνεις τα δεδομένα σου με τον τρόπο που θέλεις μέσω της βάσης σου, που -υποθέτω- θα είναι πολύ πιο εύκολο;

Άβαταρ μέλους
philos
Δημοσιεύσεις: 264
Εγγραφή: 30 Αύγ 2007 23:32

Sort πίνακα βάσει τιμής σε υπο-πίνακα

Δημοσίευση από philos » 23 Ιούλ 2014 15:23

Ο συγκεκριμένος πίνακας που σας παραθέτω, είναι ένας πίνακας που φορτώνει σε κάθε σελίδα του site σαν cache (μιλάμε για τη μηχανή vbulletin). Εφόσον φορτώνει και έχει όσα δεδομένα χρειαζόμαστε, προτιμώ να τον αξιοποιήσω αντί να τρέξω query. hmm..

Επίσης χρειάζομαι να έρχονται στην επιφάνεια, ακόμα και υπο-forums. πχ αν έχουμε:

Κώδικας: Επιλογή όλων

- HEADER CAT1 (= έχει parentid -1)
-- Tralalala
- HEADER CAT2 (= έχει parentid -1)
-- My name is George
-- I love pets
--- Lala1
--- Lala2
--- Lala3
-- I love electronics
.. και ενημερωθεί με πρόσφατη timestamp το lastpost του Lala2, το order να γίνει:

Κώδικας: Επιλογή όλων

- HEADER CAT1 (= έχει parentid -1)
-- Tralalala
- HEADER CAT2 (= έχει parentid -1)
-- My name is George
-- I love pets
--- Lala2
--- Lala1
--- Lala3
-- I love electronics
κτλ.. :)

alou
Script Master
Δημοσιεύσεις: 1374
Εγγραφή: 24 Αύγ 2007 19:52
Επικοινωνία:

Sort πίνακα βάσει τιμής σε υπο-πίνακα

Δημοσίευση από alou » 23 Ιούλ 2014 16:11

Νομίζω δεν θες απλά σορτάρισμα αλλά περισσότερες διαστάσεις (μια για κάθε επίπεδο subforum) στο array και ένα recursive sorting για να σορτάρεις ξεχωριστά το κάθε επίπεδο... αν σε βολεύει κάτι τέτοιο να το δούμε.

Άβαταρ μέλους
philos
Δημοσιεύσεις: 264
Εγγραφή: 30 Αύγ 2007 23:32

Sort πίνακα βάσει τιμής σε υπο-πίνακα

Δημοσίευση από philos » 23 Ιούλ 2014 18:20

alou έγραψε:Νομίζω δεν θες απλά σορτάρισμα αλλά περισσότερες διαστάσεις (μια για κάθε επίπεδο subforum) στο array και ένα recursive sorting για να σορτάρεις ξεχωριστά το κάθε επίπεδο... αν σε βολεύει κάτι τέτοιο να το δούμε.
Πως μπορεί να γίνει αυτό και για ποιους λόγους μπορεί να μην είναι βολικό κάτι τέτοιο;

Αν είναι απλά κάποιες διεργασίες μέσω της PHP, no prob. Απλά αφού έχουμε τα δεδομένα, δε βρίσκω λόγο να επιβαρύνω τη σελίδα με extra mysql query.

Άβαταρ μέλους
philos
Δημοσιεύσεις: 264
Εγγραφή: 30 Αύγ 2007 23:32

Sort πίνακα βάσει τιμής σε υπο-πίνακα

Δημοσίευση από philos » 25 Ιούλ 2014 21:24

Παιδιά αν ξέρετε πως θα μπορούσα να τραβήξω τα δεδομένα με σωστό order με χρήση mysql query, θα χαρώ να μου πείτε.

Όλα τα δεδομένα βρίσκονται στον πίνακα forum:
forumid
parentid
lastpost
displayorder

Τα header categories, έχουν parentid = -1 και ordάρονται βάσει της τιμής displayorder. Βασικά όλα τα forum γίνονται sort by displayorder, απλά σε αυτή την περίπτωση θέλουμε τα μη header forums να είναι order by lastpost - ανά επίπεδα.
Thanks :)

Άβαταρ μέλους
dva_dev
Script Master
Δημοσιεύσεις: 3790
Εγγραφή: 16 Σεπ 2005 01:32
Επικοινωνία:

Sort πίνακα βάσει τιμής σε υπο-πίνακα

Δημοσίευση από dva_dev » 26 Ιούλ 2014 23:00

Για κάνε μια δοκιμή με το παρακάτω:

Κώδικας: Επιλογή όλων

select forumid, parentid, lastpost, displayorder
from
(
  select forumid, parentid, lastpost, displayorder, lp, do
  from
  (
    select forumid, parentid, lastpost, displayorder, lp, displayorder do
    from forum inner join
    (
      select f.parentid pid, max(f.lastpost)+interval 1 second lp
      from forum f
      where parentid<>-1
      group by parentid
    &#41; x0
    on forumid = pid
    union
    select forum.forumid, forum.parentid, forum.lastpost, forum.displayorder, forum.lastpost lp, fp.displayorder do
    from forum
    inner join forum fp on forum.parentid=fp.forumid
  &#41; utmp
  order by do asc, lp desc, forumid desc
&#41; tmp

Άβαταρ μέλους
philos
Δημοσιεύσεις: 264
Εγγραφή: 30 Αύγ 2007 23:32

Sort πίνακα βάσει τιμής σε υπο-πίνακα

Δημοσίευση από philos » 27 Ιούλ 2014 11:44

Δεν είναι λίγο πολύπλοκο για query που θα τρέχει στην αρχική σελίδα τακτικά;

Αν δεν υπάρχει απλός τρόπος να χρησιμοποιήσουμε τον πίνακα της php κάνοντάς τον sort, θα το χρησιμοποιήσω. :)

Άβαταρ μέλους
dva_dev
Script Master
Δημοσιεύσεις: 3790
Εγγραφή: 16 Σεπ 2005 01:32
Επικοινωνία:

Sort πίνακα βάσει τιμής σε υπο-πίνακα

Δημοσίευση από dva_dev » 27 Ιούλ 2014 12:02

Δεν είναι λίγο πολύπλοκο για query που θα τρέχει στην αρχική σελίδα τακτικά;
Δεν ξέρω, εσύ θα μου πεις...

Μια δοκιμή που είχα κάνει μου φάνηκε μάλλον καλή, αλλά αν σου φαίνεται too much, τότε θα μπορούσες να αλλαγές στον πίνακα forum ή να χρησιμοποιήσεις άλλον βοηθητικό πίνακα ο οποίος να μένει πάντα ενημερωμένος ως προς το ordering σε κάθε insert και να χρησιμοποιήσεις αυτόν τον βοηθητικό.

Αυτό που δοκίμασα είναι το εξής (το γέμισα με dummy data βέβαια).

Κώδικας: Επιλογή όλων

mysql> select 'root forums' title, count&#40;*&#41; from forum where parentid=-1 union all select 'sub forums', count&#40;*&#41; from forum where parentid!=-1 union all select 'total',count&#40;*&#41; from forum;
+-------------+----------+
| title       | count&#40;*&#41; |
+-------------+----------+
| root forums |       50 |
| sub forums  |   819150 |
| total       |   819200 |
+-------------+----------+
3 rows in set &#40;0.61 sec&#41;

mysql> select count&#40;*&#41;, parentid from forum group by parentid;
+----------+----------+
| count&#40;*&#41; | parentid |
+----------+----------+
|       50 |       -1 |
|    16256 |        1 |
|    16377 |        2 |
|    16407 |        3 |
|    16139 |        4 |
|    16146 |        5 |
|    16438 |        6 |
|    16492 |        7 |
|    16511 |        8 |
|    16311 |        9 |
|    16378 |       10 |
|    16503 |       11 |
|    16401 |       12 |
|    16338 |       13 |
|    16495 |       14 |
|    16161 |       15 |
|    16355 |       16 |
|    16488 |       17 |
|    16354 |       18 |
|    16276 |       19 |
|    16613 |       20 |
|    16406 |       21 |
|    16343 |       22 |
|    16449 |       23 |
|    16490 |       24 |
|    16537 |       25 |
|    16348 |       26 |
|    16305 |       27 |
|    16315 |       28 |
|    16634 |       29 |
|    16486 |       30 |
|    16225 |       31 |
|    16403 |       32 |
|    16531 |       33 |
|    16494 |       34 |
|    16514 |       35 |
|    16116 |       36 |
|    16325 |       37 |
|    16378 |       38 |
|    16382 |       39 |
|    16289 |       40 |
|    16356 |       41 |
|    16434 |       42 |
|    16463 |       43 |
|    16350 |       44 |
|    16376 |       45 |
|    16363 |       46 |
|    16236 |       47 |
|    16269 |       48 |
|    16407 |       49 |
|    16487 |       50 |
+----------+----------+
51 rows in set &#40;1.91 sec&#41;
Eτρεξα αυτό (για να φέρει τις 10 πρώτες εγγραφές, να μην περιμένω με τις ώρες να δείξει και τις ~ 820.000 εγγραφές).

Κώδικας: Επιλογή όλων

mysql> select forumid, parentid, lastpost, displayorder from &#40;  select forumid, parentid, lastpost, displayorder, lp, do from &#40; select forumid, parentid, lastpost, displayorder, lp, displayorder do from forum inner join &#40;select f.parentid pid, max&#40;f.lastpost&#41;+interval 1 second lp from forum f where parentid!=-1 group by parentid&#41; x0 on forumid = pid  union  select forum.forumid, forum.parentid, forum.lastpost, forum.displayorder, forum.lastpost lp, fp.displayorder do from forum inner join forum fp on forum.parentid=fp.forumid &#41; utmp order by do asc, lp desc, forumid desc  &#41; tmp limit 10;
+---------+----------+---------------------+--------------+
| forumid | parentid | lastpost            | displayorder |
+---------+----------+---------------------+--------------+
|       4 |       -1 | 2014-07-26 13&#58;07&#58;01 |            1 |
|  424237 |        4 | 2014-08-10 08&#58;34&#58;08 |         5638 |
|  424192 |        4 | 2014-08-10 08&#58;31&#58;53 |         9424 |
|  424070 |        4 | 2014-08-10 08&#58;25&#58;47 |         4336 |
|  424064 |        4 | 2014-08-10 08&#58;25&#58;29 |         6416 |
|  424042 |        4 | 2014-08-10 08&#58;24&#58;23 |         2932 |
|  424037 |        4 | 2014-08-10 08&#58;24&#58;08 |         2535 |
|  424031 |        4 | 2014-08-10 08&#58;23&#58;50 |         1528 |
|  423988 |        4 | 2014-08-10 08&#58;21&#58;41 |         4165 |
|  423724 |        4 | 2014-08-10 08&#58;08&#58;29 |         9690 |
+---------+----------+---------------------+--------------+
10 rows in set &#40;12.23 sec&#41;

Άβαταρ μέλους
dva_dev
Script Master
Δημοσιεύσεις: 3790
Εγγραφή: 16 Σεπ 2005 01:32
Επικοινωνία:

Sort πίνακα βάσει τιμής σε υπο-πίνακα

Δημοσίευση από dva_dev » 27 Ιούλ 2014 12:13

Βέβαια, το θέμα είναι πόσες εγγραφές έχει ο πίνακάς σου.
Γιατί στο πλήθος που έβαλα το πρόβλημά σου δεν είναι το πόσο γρήγορα θα σου κάνει την ταξινόμηση, αλλά το πόσο γρήγορα θα πάρεις και θα δείξεις τα αποτελέσματα πίσω.
Γιατί όπως και να το κάνεις τα 12 sec δεν είναι τίποτα όταν για να δείξεις τις εγγραφές προλαβαίνεις να βγάλεις μήνυμα του χρήστη να πάει να πιει κανά καφεδάκι στην παραλία.

Αν μας πεις πόσες εγγραφές έχει ο πίνακας να το δούμε και σε php (αν και εκτιμώ ότι δεν θα έχεις βελτίωση στο χρόνο, μάλλον το ανάποδο).
Ο αλγόριθμος πάντως να έχεις υπ'όψη σου ότι θα μπορούσε να παραμείνει ο ίδιος.

Άβαταρ μέλους
philos
Δημοσιεύσεις: 264
Εγγραφή: 30 Αύγ 2007 23:32

Sort πίνακα βάσει τιμής σε υπο-πίνακα

Δημοσίευση από philos » 27 Ιούλ 2014 12:17

Οι εγγραφές είναι γύρω στις 320-380 :)

Τα 12 seconds είναι πολλά για query που τρέχει τακτικότατα. :p
Μπορείς να μου πεις πόσα seconds θέλει για 350-400 εγγραφές;

Θα πρέπει να επιστρέφονται όλα τα forums με το σωστό sorting (δλδ δεν υπάρχει limit).

Σε ευχαριστώ!

Απάντηση

Επιστροφή στο “PHP Προγραμματισμός”

Μέλη σε σύνδεση

Μέλη σε αυτήν τη Δ. Συζήτηση: Δεν υπάρχουν εγγεγραμμένα μέλη και 1 επισκέπτης