gin Posted November 7, 2007 Share Posted November 7, 2007 This has been giving me SUCH a headache I have an array like so (of course, there are many more items than shown): <?php Array ( [0] => Array ( [award] => Finalist - Public Service Messages and Cause Appeal Category [year] => 2006 [name] => Big Huge Award [project] => 20 [section] => animation [brand] => asdf [title] => Funky title ) ) ?> I want to sort it by [award] in this order: Gold, Silver, Bronze, Finalist. I'm getting nowhere with uksort. The problem is the callback function. So far I've got: <?php function cmp($a, $b) { $sortorder = array('gold', 'silver', 'bronze', 'finalist'); if ($a['position'] == $b['position']) return strcmp($a['name'], $b['name']); $cmpa = array_search($a['position'], $sortorder); $cmpb = array_search($b['position'], $sortorder); return ($cmpa > $cmpb) ? 1 : -1; } ?> I need to modify this so that the keywords 'gold', 'silver', etc. are picked out of the long [award] field. Could someone point me on my way? Quote Link to comment Share on other sites More sharing options...
ToonMariner Posted November 7, 2007 Share Posted November 7, 2007 this is about how you set your array up. In terms of searching an array with the availble php functions and constructs its actually better to group your sub arrays by their type.... SO you would have... Array ( 'award' => array('Finalist - Public Service Messages and Cause Appeal Category', 'Finalist - Private Death Camp Service in Guantanamo', .....), 'year' => array(2006,2007,....) .... and so on. ); this would allow you to search the types you want or apply array_multisort to the array and do what ever... now I could put som emore code down - but then you would lose teh pleasure of learning it yourself and seeing how much easier it is to work with an array constructed as I have shown..) Quote Link to comment Share on other sites More sharing options...
gin Posted November 7, 2007 Author Share Posted November 7, 2007 Thanks very much for your reply! Your code piece makes no sense to me, but if I'm reading the explanation correctly... well this is my attempt: <?php Array ( [some Award] => Array ( [4] => Array ( [0] => Array ( [award] => Finalist - PSA [year] => 2006 [name] => Some Award [project] => 20 ) ) ) [some Other Award] => Array ( [4] => Array ( [0] => Array ( [award] => Finalist - PSA [year] => 2006 [name] => Some Other Award [project] => 26 ) [1] => Array ( [award] => Finalist - yadda yadda [year] => 2007 [name] => Some Other Award [project] => 26 ) ) [1] => Array ( [0] => Array ( [award] => Gold - Animation [year] => 2006 [name] => Some Other Award [project] => 4 ) ) ) ) ?> Now however, to my utter annoyance, the Finalists are listed before the Gold. Is there any way to use array_multisort to sort according to keys, or should I just give in and foreach-ksort my way through? Quote Link to comment Share on other sites More sharing options...
aschk Posted November 7, 2007 Share Posted November 7, 2007 I disagree with that (ToonMariner) and believe it's all down to preference. Personlly i like the format that has been chosen by gin. It allows extra fields to be added to certain items and not to others. Using your array setup (which is just as valid) i would have to make sure that i created a new array and populated it with mostly blank information except for the particular item i wanted to added the extra field to. Not ideal. Also array_multisort only has a view available options, regex, numeric, or string, of which gin's pattern fits none. This might just be my technical inexperience of usage of array_multisort but that's the impression i get from the php docs. What you need to define is your own sorting algorithm. Quote Link to comment Share on other sites More sharing options...
aschk Posted November 7, 2007 Share Posted November 7, 2007 Having just read your latest post your array of information appears to have changed from the first post. What DOES it look like? Quote Link to comment Share on other sites More sharing options...
gin Posted November 7, 2007 Author Share Posted November 7, 2007 The array is actually generated from a database. All items have the same fields, so that's not an issue. The second post is my attempt at a brute force method of sorting (if it can be called that). It's just the same information placed in the order I'll eventually want to display it in. The display, incidentally, will look something like: Some Award - Gold - Bestest in the world Title: asdf asdf (2006) - Finalist - PSA Title: qwer qwer (2006) Some Other Award - Gold - Bestest in the world Title: asdf asdf (2006) - Silver - PSA Title: qwer qwer (2006) Anyway, I'm kinda resigned to the foreach-ksort method at the moment. I was just hoping someone knew of a sort I'd never heard of that would do all I want without the gazillion loops. Quote Link to comment Share on other sites More sharing options...
ToonMariner Posted November 7, 2007 Share Posted November 7, 2007 @aschk - by all means disagree but the proof is in the pudding! The array I porposed is MUCH easier to work with... @gin you have managed to create a 3D array which will be even harder to work with!!! you have got hung up on keeping all the data of one record grouped together... think of your database table - its a series of records that all have a field - my array is just that it stores teh the data for each field in one array and the association is by the key - just as the database i stored in fileds and the association is made by the record number... you shoudl end up with a 2-D array like so... <?php $array = array ( 'award' => array ( 'Finalist - Public Service Messages and Cause Appeal Category', 'Finalist - Private Death Camp Service in Guantanamo', ..... ), 'year' => array ( 2006, 2007, .... ) ); .... and so on. ?> the you could do somethink like $findyear = array_keys($array['year'], 2007); the result would be all the keys of $array['year'] that were 2007 and use them to get the information out of the other arrays (like $array['award']) using those keys. Because you have this associative key you have much more flexibility in what you can achieve... Quote Link to comment Share on other sites More sharing options...
Barand Posted November 7, 2007 Share Posted November 7, 2007 <?php function cmp($a, $b) { $pos = array ( 'gold' => 1, 'silver' => 2, 'bronze' => 3, 'finalist' => 4 ); list ($a1, $c1) = explode('-', $a['award']); list ($a2, $c2) = explode('-', $b['award']); $catcmp = strcmp(trim($c1), trim($c2)); if ($catcmp==0) return $pos[trim($a1)] - $pos[trim($a2)]; else return $catcmp; } usort ($myarray, 'cmp'); usort ($myarray, 'cmp'); ?> Quote Link to comment Share on other sites More sharing options...
aschk Posted November 7, 2007 Share Posted November 7, 2007 Okey dokey, having taken your example toon i've written it out a little further with some sample data. This is what i'm after... All the awards for the year 2007, ORDERED as gold, then silver, then bronze, then finalists... <?php $array = array ( 'award' => array ( 'Finalist - Public Service Messages and Cause Appeal Category', 'Finalist - Private Death Camp Service in Guantanamo', 'Finalist - 3rd post', 'Silver - ertae aerg aer g', 'Gold - lkerjgklaejr arar', 'Bronze - el;araek lrjlkrja', ), 'year' => array ( 2006, 2007, 2007, 2007, 2007, 2007, ) ); $findyear = array_keys($array['year'], 2007); for($i = 0; $i<count($findyear); $i++){ echo $array["award"][$i]."<br/>"; } ?> What we have in the above a list of awards... fantastic, but how do you order then??? I think you've missed the point of the question. I'm going to propose that your database structure could use some modification gin. You need a separate field for "position" with it being "gold", "silver", "bronze", or "finalist" linked by another table, with an "order" column also. Thus you can have Award_Types #################### id | type | order ==================== 1 | gold | 1 2 | bronze | 3 3 | finalist | 4 4 | silver | 2 Now should you ever have another position (platinum) you just add it in at the bottom and rejig your ordering, AND voila your SQL statement will STILL continue to order by the order in the table. Quote Link to comment Share on other sites More sharing options...
Barand Posted November 7, 2007 Share Posted November 7, 2007 The main problem that structure is it tries to squeeze 2 columns into one. Finalist - Public Service Messages and Cause Appeal Category should be this, at least [pre] | award | category | ------------|--------------------------------------------+ | Finalist | Public Service Messages and Cause Appeal | [/pre] and better still if category were a foreign key linked to a category table. Then you do a sort in the original guery SELECT * FROM awardtable ORDER BY category, FIELD(award, 'gold', 'silver', 'bronze', 'finalist') Quote Link to comment Share on other sites More sharing options...
aschk Posted November 7, 2007 Share Posted November 7, 2007 Nice variation on my solution Barand I should just explain the reasoning behind my solution better : Your SQL statement doesn't change if you add another category, where as in Barand's example you need to alter your SQL statement. Mine would be ORDER BY award_category.`order` no matter how many categories you have. Also, Barand's option provides no referential integrity for your data, meaning you could have "Finalist" , "finalist", "finlist", or some other horrid variation your input. Quote Link to comment Share on other sites More sharing options...
ToonMariner Posted November 7, 2007 Share Posted November 7, 2007 What we have in the above a list of awards... fantastic, but how do you order then??? I think you've missed the point of the question. array_multisort() IF you take barands advice on the 'award' field but store numeric values 1-4 with 1 representing gold, 2 silver and so on this will be a piece of excreation.... Quote Link to comment Share on other sites More sharing options...
aschk Posted November 7, 2007 Share Posted November 7, 2007 Can you elaborate on my test example then using array_multisort so that I may see a working solution. Also, yes you're correct you could interchange numeric values with the names, however where do you change the numbers for their string representations? PHP Constants? They lose their meaning if you just use numbers, hence the extra table requirement. Of course you could just interpret those numeric in PHP, but with what? Constants? Is it maintable, nope Of course at the end of the day, each person's choice is there own and i'm sure gin will find an applicable solution be it one of ours or not. All are valid, and i'm certainly not trying to preach or control any particular channel of thinking on the matter. Just trying to offer another solution, with drawbacks/pitfalls and all. I will continue to be a PHP pest until I can't see the faults in others and my own designs Quote Link to comment Share on other sites More sharing options...
Barand Posted November 7, 2007 Share Posted November 7, 2007 Nice variation on my solution Barand Sorry, I didn't know it was you who held the patent on "normalisation". And I must have missed the bit where you split off the category from the award level. Quote Link to comment Share on other sites More sharing options...
gin Posted November 9, 2007 Author Share Posted November 9, 2007 Thank you everyone for all your suggestions. Right now, for the sake of expediency, I'm using nested loops, but I'm certainly interested in learning how to work smarter. @ToonMariner: Your solution is definitely close to what I'm looking for, assuming I can wrap my brain around the array_multisort(). I need to go tinker with my code and try out Barand's code. @Barand & aschk: I did in fact consider separating the award and category into different fields. Unfortunately, the awards aren't so cooperative as to have plain old "gold, silver, bronze" awards. It varies from Gold to Gold World Medal to Winner to.... you get the idea. Frankly, I should have just added another field, "sort_order", or similar. This is what I get for not planning things out properly. Quote Link to comment Share on other sites More sharing options...
gin Posted November 10, 2007 Author Share Posted November 10, 2007 In the end I added a sort field to the db. This way I can leave all the sorting to MySQL. Note to self: plan better. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.