moagrius Posted August 20, 2010 Share Posted August 20, 2010 hi, i'm trying to sort an array of associative arrays, based on one of the keys. if the value of the key is a primitive, normal sorting occurs - this works fine. if the value of the key is an array, i'd like to have it sorted by "groups" here's an example: <?php $data[] = array('name' => 'h', 'list' => array(1,2)); $data[] = array('name' => 'g', 'list' => array(1)); $data[] = array('name' => 'a', 'list' => array(1,3)); $data[] = array('name' => 'f', 'list' => array(2)); $data[] = array('name' => 'e', 'list' => array(2,3)); $data[] = array('name' => 'b', 'list' => array(3)); $data[] = array('name' => 'c', 'list' => array(1,2,3,4)); $data[] = array('name' => 'd', 'list' => array(3,4)); function deep_sort($array, $sorton){ usort($array, function($a, $b) use($sorton) { $a = $a[$sorton]; $b = $b[$sorton]; if(is_array($a) && is_array($b)){ // this bit is obviously flawed - only included for illustrative purposes $a = implode('', $a); $b = implode('', $b); } return ($a == $b) ? 0 : ($a > $b) ? 1 : -1; }); return $array; } $sorted_by_name = deep_sort($data, 'name'); print '<pre>'; print_r($sorted_by_name); print '</pre>'; $sorted_by_list = deep_sort($data, 'list'); print '<pre>'; print_r($sorted_by_list); print '</pre>'; ?> the sorted_by_name bit is fine - but for sorted_by_list, what i want returned is all the array ordered as follows: all those with "1" (or the lowest if none have "1") in it's list value first, then all those remaining that have the next highest ("2"), etc. so right now, the returns for sort_by_list look like this: Array ( [0] => Array ( [name] => g [list] => Array ( [0] => 1 ) ) [1] => Array ( [name] => f [list] => Array ( [0] => 2 ) ) [2] => Array ( [name] => b [list] => Array ( [0] => 3 ) ) [3] => Array ( [name] => h [list] => Array ( [0] => 1 [1] => 2 ) ) [4] => Array ( [name] => a [list] => Array ( [0] => 1 [1] => 3 ) ) [5] => Array ( [name] => e [list] => Array ( [0] => 2 [1] => 3 ) ) [6] => Array ( [name] => d [list] => Array ( [0] => 3 [1] => 4 ) ) [7] => Array ( [name] => c [list] => Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 4 ) ) ) whereas i'd like to get back: Array ( [0] => Array ( [name] => g [list] => Array ( [0] => 1 ) ) [1] => Array ( [name] => h [list] => Array ( [0] => 1 [1] => 2 ) ) [2] => Array ( [name] => c [list] => Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 4 ) ) [3] => Array ( [name] => a [list] => Array ( [0] => 1 [1] => 3 ) ) [4] => Array ( [name] => f [list] => Array ( [0] => 2 ) ) [5] => Array ( [name] => e [list] => Array ( [0] => 2 [1] => 3 ) ) [6] => Array ( [name] => b [list] => Array ( [0] => 3 ) ) [7] => Array ( [name] => d [list] => Array ( [0] => 3 [1] => 4 ) ) ) TYIA for any suggestions Quote Link to comment Share on other sites More sharing options...
sasa Posted August 20, 2010 Share Posted August 20, 2010 try to change $a = implode('', $a); $b = implode('', $b); to $a = implode('', $a).'a'; $b = implode('', $b).'a'; not tested Quote Link to comment Share on other sites More sharing options...
Psycho Posted August 20, 2010 Share Posted August 20, 2010 I couldn't get your code to run - getting an error about defining the function as a parameter for some reason. But, I was able to get the logic needed. Basically you need to test the min()'s of the two arrays. If the mins are not equal then sort the lowest min first. If they are equal you need to remove those min values and test the new mins. This process continues until you get unequal mins or until one or both arrays run out of values. If you get two different mins the array with the lowest min gets sorted first. If one array runs out of values it is sorted first. If both arrays run out of values (they had the exact same values) return 0; Here is the function I used. I'll leave it to you to determine how to implement the logic into your existing code: function sort_by_array ($a, $b) { $a = $a['list']; $b = $b['list']; //Continue to remove the min value from each array until //they are not equal or until one runs out of values while(count($a)>0 && count($b)>0 && min($a)==min($b)) { unset($a[array_search(min($a), $a)]); unset($b[array_search(min($b), $b)]); } //$a and $b have different min values if(count($a)>0 && count($b)>0) { return (min($a)>min($b))?1:-1; } //One or both arrays ran out of values return (count($a)!=count($b)) ? (count($a)==0)?-1:1 : 0; } Quote Link to comment Share on other sites More sharing options...
moagrius Posted August 21, 2010 Author Share Posted August 21, 2010 awesome - tested against a randomly populated dataset with 5000 items and much larger versions of "list" and it still holds up. i've got this question on several boards and mailing lists and while we've come close with about 9 different approaches, yours appears complete and bullet-proof. thank you! Quote Link to comment Share on other sites More sharing options...
Psycho Posted August 21, 2010 Share Posted August 21, 2010 Yeah, some of the most difficult things to do with programming are ones that are "obvious" to a human. The trick is to walk throuh the problem and break it down into specific steps - before you write the first line of code. Please mark the topic as solved. 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.