philos Δημοσ. 7 Αυγούστου 2014 Δημοσ. 7 Αυγούστου 2014 Έχουμε τον παραδειγματικό πίνακα σε PHP (σας παρουσιάζω το var_dump του). 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) [...] Αυτός ο πίνακας μας δίνει την ακόλουθη λίστα forums: - 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.Επίσης χρειάζομαι να έρχονται στην επιφάνεια, ακόμα και υπο-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 Καμιά ιδέα;
exarhis Δημοσ. 7 Αυγούστου 2014 Δημοσ. 7 Αυγούστου 2014 function array_sort_by_column(&$arr, $col, $dir = SORT_ASC) { $sort_col = array(); foreach ($arr as $key => $row) { $sort_col[$key] = $row[$col]; } array_multisort($sort_col, $dir, $arr); } array_sort_by_column($array, 'lastpost'); Αυτή η function ταξινομεί το array. $array = array_reverse($array); Αλλά το βγάζει με ταξινόμηση με φθίνουσα σειρά , έτσι το αντιστρέφουμε
philos Δημοσ. 7 Αυγούστου 2014 Μέλος Δημοσ. 7 Αυγούστου 2014 Δεν την έχω δοκιμάσει, ωστόσο απ ότι καταλαβαίνω, κάνει όλα τα forums sort by lastpost. Εγώ θέλω τα header forums (parentid = -1) να μην αλλάζουν θέση, αλλά να αλλάζουν θέση μόνο τα υπο-forums τους ανά επίπεδο πάντα. Ευχαριστώ
defacer Δημοσ. 7 Αυγούστου 2014 Δημοσ. 7 Αυγούστου 2014 Ο πίνακάς σου δεν έχει δομή, είναι μια χύμα λίστα φόρουμ. Τα αποτελέσματα που θέλεις όμως προφανώς βασίζονται σε συγκεκριμένη δομή (που προκύπτει από τα parent id). Κατα συνέπεια βάλε πρώτα δομή στα δεδομένα σου (κάντα δέντρο αντί για λίστα) και στη συνέχεια αυτό που θέλεις γίνεται εύκολα με recursive walk του δέντρου. Διαφορετικά απλά θα μαζοχίζεσαι κάνοντας τη ζωή αχρείαστα δύσκολη. @exarhis: Ίσως σ' ενδιαφέρει να δεις μια σχετική απάντησή μου στο StackOverflow. 3
exarhis Δημοσ. 7 Αυγούστου 2014 Δημοσ. 7 Αυγούστου 2014 defacer εξτρεμιστικός ο κώδικας σου, πρώτη φορά βλέπω return μια function και μετά το use : return function($first, $second) use (&$criteria) Μήπως μπορείς να μου εξηγήσεις τι σημαίνουν αυτά. Εγώ αυτοδίδακτος είμαι. @philos Αν μπορείς χώρισε τα σε 2 array το ένα με το -1 και το άλλο με τα subforum
alou Δημοσ. 7 Αυγούστου 2014 Δημοσ. 7 Αυγούστου 2014 @philos, ξεκίνα κάπως έτσι και μετά usort με το πεδίο που θες recursively $Categorys = array( 1 => array('id'=>1, 'title'=>'Category 1', 'parentId'=> '-1', 'updated'=>1233), 2 => array('id'=>2, 'title'=>'Category 2', 'parentId'=> '-1', 'updated'=>124), 3 => array('id'=>3, 'title'=>'Category 1.1', 'parentId'=>'1', 'updated'=>3440), 4 => array('id'=>4, 'title'=>'Category 1.1.1', 'parentId'=>'3', 'updated'=>821), 5 => array('id'=>5, 'title'=>'Category 2.1', 'parentId'=>'2', 'updated'=>133), 6 => array('id'=>6, 'title'=>'Category 1.1.2', 'parentId'=>'3', 'updated'=>223), 7 => array('id'=>7, 'title'=>'Category 1.1.3', 'parentId'=>'3', 'updated'=>423), 8 => array('id'=>8, 'title'=>'Category 1.2', 'parentId'=>'1', 'updated'=>155) ); function makeTree($categorys) { $rv = array(); foreach( $categorys as $cat) { //top level only if ( $cat['parentId'] == '-1' ) { $rv[$cat['id']] = $cat; } else { //parent id $pid = $cat['parentId']; $ppid = $pppid = false; if ($pid != '-1'){ //parent's parent id $ppid = $categorys[$pid]['parentId']; } if ($ppid && $ppid != '-1'){ $pppid = $categorys[$ppid]['parentId']; } //handling 3rd level if ($pppid) { if (!isset($rv[$ppid])){ $rv[$ppid] = array(); } if (!isset($rv[$ppid]['children'])){ $rv[$ppid]['children'] = array(); } if (!isset($rv[$ppid]['children'][$pid])){ $rv[$ppid]['children'][$pid] = array(); } if (!isset($rv[$ppid]['children'][$pid]['children'])){ $rv[$ppid]['children'][$pid]['children'] = array(); } $rv[$ppid]['children'][$pid]['children'][$cat['id']] = $cat; //ouf } else if ($ppid) { //handling 2nd level if (!isset($rv[$pid])){ $rv[$pid] = array(); } if (!isset($rv[$pid]['children'])){ $rv[$pid]['children'] = array(); } $rv[$pid]['children'][$cat['id']] = $cat; } else { //handling 1st level if (!isset($rv[$pid])){ $rv[$pid] = array(); } if (!isset($rv[$pid]['children'])){ $rv[$pid]['children'] = array(); } $rv[$pid]['children'][$cat['id']] = $cat; } } } return $rv; } που θα φτιάξει μια τέτοια δομή, όπως είπε και ο defacer αλλιώς δεν κάνεις δουλειά array(2) { [1]=> array(5) { ["id"]=> int(1) ["title"]=> string(10) "Category 1" ["parentId"]=> string(2) "-1" ["updated"]=> int(1233) ["children"]=> array(2) { [3]=> array(5) { ["id"]=> int(3) ["title"]=> string(12) "Category 1.1" ["parentId"]=> string(1) "1" ["updated"]=> int(3440) ["children"]=> array(3) { [4]=> array(4) { ["id"]=> int(4) ["title"]=> string(14) "Category 1.1.1" ["parentId"]=> string(1) "3" ["updated"]=> int(821) } [6]=> array(4) { ["id"]=> int(6) ["title"]=> string(14) "Category 1.1.2" ["parentId"]=> string(1) "3" ["updated"]=> int(223) } [7]=> array(4) { ["id"]=> int(7) ["title"]=> string(14) "Category 1.1.3" ["parentId"]=> string(1) "3" ["updated"]=> int(423) } } } [8]=> array(4) { ["id"]=> int(8) ["title"]=> string(12) "Category 1.2" ["parentId"]=> string(1) "1" ["updated"]=> int(155) } } } [2]=> array(5) { ["id"]=> int(2) ["title"]=> string(10) "Category 2" ["parentId"]=> string(2) "-1" ["updated"]=> int(124) ["children"]=> array(1) { [5]=> array(4) { ["id"]=> int(5) ["title"]=> string(12) "Category 2.1" ["parentId"]=> string(1) "2" ["updated"]=> int(133) } } } }
defacer Δημοσ. 7 Αυγούστου 2014 Δημοσ. 7 Αυγούστου 2014 defacer εξτρεμιστικός ο κώδικας σου, πρώτη φορά βλέπω return μια function και μετά το use : return function($first, $second) use (&$criteria) Μήπως μπορείς να μου εξηγήσεις τι σημαίνουν αυτά. Εγώ αυτοδίδακτος είμαι. Από την 5.3 και μετά μπορείς να χρησιμοποιήσεις μια function (η οποία δε θα έχει όνομα και γι' αυτό λέγεται anonymous function) όπως οποιαδήποτε άλλη τιμή. Για παράδειγμα, να τη βάλεις μέσα σε μια μεταβλητή: $greeter = function($what) { echo "Hello $what!"; }; $greeter("world"); // και την καλείς έτσι, κανονικά περνάς παραμέτρους κλπ Επίσης μπορείς να την περάσεις σαν όρισμα σε ή να την κάνεις return από μια δεύτερη function, η οποία τότε ονομάζεται higher order function: // η make_greeter είναι higher order function function make_greeter() { return function() { echo "Hello world!"; }; // που επιστρέφει μια anon function } $greeter = make_greeter(); $greeter(); Φυσικά η higher order function θα μπορούσε να είναι κι αυτή anon, δεν αλλάζει κάτι ιδιαίτερο: $make_greeter = function() { return function() { echo "Hello world!"; }; } $greeter = $make_greeter(); // καλείς την higher order anon που επιστρέφει μια άλλη anon $greeter(); // την οποία καλείς στη συνέχεια Με το use μπορείς να σχηματίσεις closure σε μια anon function. Με απλά λόγια, μπορείς να βάλεις την PHP να θυμάται μέρος του "περιβάλλοντος" στο σημείο όπου δημιουργείς την anon function ούτως ώστε αυτό το περιβάλλον να χρησιμοποιηθεί στο σημείο που την καλείς -- το οποίο μπορεί να είναι σε παντελώς άσχετο τμήμα του προγράμματος εφόσον μπορείς να τη βάλεις σε μια μεταβλητή και να την πας βόλτα κλπ. Παράδειγμα: function make_greeter() { $what = "world"; return function() use ($what) { echo "Hello $what!"; }; } $greeter = make_greeter(); $greeter(); Εδώ όπως βλέπεις στην κλήση του greeter κάπως θυμόμαστε ότι υπήρχε μια μεταβλητή $what στο σημείο όπου δημιουργήσαμε την anon function και ότι είχε την τιμή "world" παρόλο που στο σημείο όπου καλέσαμε τον greeter δεν υπάρχει καμία τέτοια μεταβλητή πλέον. Το αμέσως επόμενο βήμα είναι να σκεφτείς ότι η $what μπορεί κάλλιστα να είναι όρισμα της make_greeter, πχ function make_greeter($what) { return function() use ($what) { echo "Hello $what!"; }; } $greeter = make_greeter("world"); $greeter(); // Hello world! $greeter = make_greeter("php"); $greeter(); // Hello php! Και τέλος για να φτάσεις σε κώδικα ισοδύναμο με της απάντησης κάνεις και closure και δίνεις στην anon function παραμέτρους: function make_greeter($greeting) { return function($what) use ($greeting) { echo "$greeting $what!"; }; } $say_hello = make_greeter("Hello"); $say_hello("world"); $say_hello("php"); $say_goodbye = make_greeter("Goodbye"); $say_goodbye("world"); Το σχετικό τμήμα του manual δυστυχώς δεν είναι πολύ κατατοπιστικό, αλλά αφού εξοικειωθείς με την ιδέα μπορείς να διαβάσεις περισσότερα σε tutorials άλλων γλωσσών (π.χ. τέτοια πράγματα γίνονται όλη την ώρα στη JavaScript) -- η σύνταξη και κάποιες λεπτομέρειες αλλάζουν αλλά είναι οι ίδιες ιδέες και μπορείς να τις μεταφέρεις από τη μία γλώσσα στην άλλη. Ο κώδικας της απάντησης βασίζεται στην απλή ιδέα ότι για να κάνεις "σοβαρή δουλειά" αναγκαστικά πρέπει να πας σε usort και σια, όμως τότε είναι μπελαλίδικο το να ορίζεις κάθε φορά την καστομιά του sort και ειδικά αν αυτό που θέλεις είναι απλά να πάρεις ένα $col μέσα από κάθε υποπίνακα. Οπότε βάζεις ανάμεσα μια δική σου function (τη make_comparer) η οποία κανονίζεις να έχει την όποια βολική κλήση θέλεις και να κάνει τη βρώμικη δουλειά του να φτιάχνει την καστομιά από τις πληροφορίες που της δίνεις. 2
alou Δημοσ. 8 Αυγούστου 2014 Δημοσ. 8 Αυγούστου 2014 Εξαιρετική εξήγηση με αρκετά "aha!", thanks defacer. Τα closures αν είσαι συνηθισμένος από JavaScript έχουν διαφορετική συμπεριφορά στην PHP και το πρώτο που είχα καταλάβει και θεώρησα σαν λόγο ύπαρξης του use() στα anon ήταν κάτι σαν το παρακάτω: //JS var w = "Hello"; var sayHi = function() { console.log(w + " world"); } sayHi(); //Hello world //PHP $w = "Hello"; $sayHi = function(){ echo $w." world"; } $sayHi(); //$w einai undefined //οποτε πάμε με τη σύνταξη του "use" $sayHi = function() use ($w){ echo $w." world"; } $sayHi();//Hello world Αν κάπου μετά στον κώδικα αλλάζει η τιμή του $w η php θα κρατήσει την τιμή που ορίστηκε πριν οριστεί η function, νομίζω, εκτός αν οριστεί με referenece το use(&$w) ενώ στην js δεν ισχύει αυτό.
geomagas Δημοσ. 8 Αυγούστου 2014 Δημοσ. 8 Αυγούστου 2014 Όλα είναι θέμα scope. Στην php το κάθε κομμάτι κώδικα που τρέχει, "βλέπει" μόνο τις μεταβλητές που ορίζονται μέσα στη function στην οποία "ζει". Μέχρι εκεί. Ένα scope και τέλος. Το οποίο βέβαια καταστρέφεται μετά το τέλος της function. Αν θέλει λοιπόν κάποιος να χρησιμοποιήσει μεταβλητές από άλλο scope, θα πρέπει με κάποιον τρόπο να τις εισάγει μέσα σε αυτό της function. Ένας τρόπος είναι η χρήση της global. Και για να ακριβολογούμε, το ακριβές αντίστοιχο του js παραδείγματός σου (χωρίς άλλες υποθέσεις) είναι αυτό: $w = "Hello"; $sayHi = function(){ global $w; echo $w." world"; } Τι γίνεται όμως αν θέλεις να κάνεις κάτι τέτοιο: $hiWrapper=function() { $w = "Hello"; $sayHi = function(){ echo $w." world"; } } Εδώ το $w δεν είναι global για να μπορείς να χρησιμοποιήσεις την ...εχμ... global, αλλά δεν ανήκει και στο scope της $sayHi. Είναι κάπου ενδιάμεσα, και η php δεν έχει την "ορατότητα" να το δει, σε αντίθεση με την js. Εδώ έρχεται η use(), που δεν είναι τίποτε άλλο από μία αντιγραφή (σε αντίθεση με την global) κάποιων μεταβλητών της "εξωτερικής" function στο scope της εσωτερικής: $hiWrapper=function() { $w = "Hello"; $sayHi = function() use($w) { echo $w." world"; } } Και πάλι όμως εννοείται ότι αυτό συμβαίνει σε ένα μόνο επίπεδο. Για παραπάνω επίπεδα, θα πρέπει να "προωθήσουμε" τη μεταβλητή ρητά, από το κάθε εξωτερικό scope στο κάθε εσωτερικό, μέχρι αυτό που τλεικά τη χρησιμοποιεί: $hiWrapper=function() { $w = "Hello"; $hiCocoon=function() use($w) { $sayHi = function() use($w) { echo $w." world"; } } } 1
alou Δημοσ. 8 Αυγούστου 2014 Δημοσ. 8 Αυγούστου 2014 Ναι, προφανώς είναι θέμα scope και θα βάλω στις περιπτώσεις και κάποια ακόμα: $h = "Hello"; $sayHi = function() use ($h) { echo $h." world"; }; $h = "Goodbye"; $sayHi();//Hello world Ενώ με reference $h = "Hello"; $sayHi = function() use (&$h) { echo $h." world"; }; $h = "Goodbye"; $sayHi();//Goodbye world Ευκολάκι το μπέρδεμα, αν δουλεύεις παράλληλα php και js :/ Edit: θα μπορούσε και αυτό που περνάς στο use να είναι anonymous function, διαπίστωσα, και έχει αρκετό ενδιαφέρον... $sayHi = function($who) use (&$h) { echo $h()." ".$who; }; $h = function(){ return time(h) / 3600 > 12 ? "Goodevening" : "Goodmorning"; }; $sayHi("world");
geomagas Δημοσ. 8 Αυγούστου 2014 Δημοσ. 8 Αυγούστου 2014 Ναι, εξ ου και τα bold στην "αντιγραφή" παραπάνω. Αυτή η αντιγραφή γίνεται κατά τον ορισμό της function κι όχι κατά την εκτέλεσή της. Έτσι, αν το κάνεις by-val θα αντιγράψει το value, αν το κάνεις by-ref θα αντιγράψει το reference. Στην js δεν γίνεται καμία αντιγραφή πουθενά, διότι απλούστατα η function βλέπει κι άλλα scopes εκτός το δικό της. Οπότε, κατά το χρόνο εκτέλεσης, απλά αναφέρεσαι στη μεταβλητή όπως είναι εκείνη τη στιγμή.
Προτεινόμενες αναρτήσεις
Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε
Πρέπει να είστε μέλος για να αφήσετε σχόλιο
Δημιουργία λογαριασμού
Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!
Δημιουργία νέου λογαριασμούΣύνδεση
Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.
Συνδεθείτε τώρα