Sorting a multidimensional array in PHP

I am currently creating a sort method consisting of values ​​from a mysql query.

Here is a brief overview of the array:

Array ( [0] => Array ( ['id'] = 1; ['countries'] = 'EN,CH,SP'; ) [1] => Array ( ['id'] = 2; ['countries'] = 'GE,SP,SV'; ) ) 

I managed to make normal use based on the values ​​of the numeric identifier, but I prefer to sort the array by the contents of the "country" field (if in this case it contains the specified string, country code), and then by the id field.

The following snippet was my first idea on how to do this, but I have no idea how to include it in a working function:

 in_array('EN', explode(",",$a['countries']) ); 

How do you do that?

Thank!




Unfortunately, I do not understand anything.

Here is what I have at the moment, and it gives me nothing but errors: uasort() [function.uasort]: Invalid comparison function

 function compare($a, $b) { global $usercountry; if ( in_array($usercountry, $a['countries']) && in_array($usercountry, $a['countries']) ) { $return = 0; } else if (in_array($usercountry, $a['countries'])) { $return = 1; } else { $return = -1; } return $return; } $array= usort($array, "compare"); 

Is there anyone who could give me a hint on how to proceed?

+5
arrays php multidimensional-array usort
Jan 13 '10 at 18:37
source share
5 answers

Personally, I would use a custom (anonymous) function in combination with usort() .

EDIT: Re is your comment. Hope this puts you on the right track. This function gives equal priority to elements that have an EN, or do not have an EN, or adjusted priority when only one has an EN.

 usort($array,function ($a, $b) { $ac = strpos($a['countries'],'EN'); $bc = strpos($a['countries'],'EN'); if (($ac !== false && $bc !== false) || ($ac == false && $bc == false)) { return 0; } elseif ($ac !== false) { return 1; } else { return -1; } }); 

This function, on the other hand, gives equal priority if both have an EN, higher if there is an EN, and compares the text if neither of them has an EN.

 usort($array,function ($a, $b) { $ac = strpos($a['countries'],'EN'); $bc = strpos($a['countries'],'EN'); if ($ac !== false && $bc !== false)) { return 0; } elseif ($ac !== false) { return 1; } elseif ($bc !== false) { return -1; } else { if ($a['countries'] == $b['countries']) { return 0; } elseif($a['countries'] > $b['countries']) { return 1; } else { return -1; } } }); 

Again, hopefully this will give you enough opportunity to move forward on your own. If you have any problems, feel free to leave more comments and I will try to help. Note, if you are linking several properties to weight: try a funky lock block, for example.

 $ac = array_flip(explode(',',$a['countries'])); $bc = array_flip(explode(',',$b['countries'])); switch (true) { case array_key_exists('EN',$ac) && !array_key_exists('EN',$bc): return 1; case array_key_exists('DE',$ac) && !array_key_exists('EN',$bc) && !array_key_exists('EN',$bc): return 1; // and so on } 

Additional changes!

Actually, I was thinking more about the problem of complex sorting, and for your consideration I came up with the following solution. This will allow you to define numerical ratings based on the keywords that appear in the country index. Here is the code, including an example:

Array Example

 $array = array( array( 'countries' => 'EN,DE,SP', ), array( 'countries' => 'EN,CH,SP', ), array( 'countries' => 'DE,SP,CH', ), array( 'countries' => 'DE,SV,SP', ), array( 'countries' => 'EN,SP,FR', ), array( 'countries' => 'DE,FR,CH', ), array( 'countries' => 'CH,EN,SP', ), ); 

The sort order

 $rankings = array( 'EN' => 10, 'SP' => 8, 'FR' => 7, 'DE' => 5, 'CH' => 3, 'SV' => 1, ); usort($array, function (&$a, &$b) use ($rankings) { if (isset($a['_score'])) { $aScore = $a['_score']; } else { $aScore = 0; $aCountries = explode(',',$a['countries']); foreach ($aCountries as $country) { if (isset($rankings[$country])) { $aScore += $rankings[$country]; } } $a['_score'] = $aScore; } if (isset($b['_score'])) { $bScore = $b['_score']; } else { $bScore = 0; $bCountries = explode(',',$b['countries']); foreach ($bCountries as $country) { if (isset($rankings[$country])) { $bScore += $rankings[$country]; } } $b['_score'] = $bScore; } if ($aScore == $bScore) { return 0; } elseif ($aScore > $bScore) { return -1; } else { return 1; } }); 

Note. This code sorts the highest rating at the top of the array . If you want to change the behavior, change this:

  elseif ($aScore > $bScore) { 

to

  elseif ($aScore < $bScore) { 

Please note that more than was changed to a smaller character. Making this change will sort the lower ranking entries at the top of the array . Hope all this helps!

NOTE ALSO!

This code will make a small change to your array by adding the _score element to each array. I hope this is not a problem, since by preserving this value, I literally was able to increase the speed by more than two times (.00038 -.00041 to .00016 -.00018 in my tests). If not, remove the if blocks that retrieve the cached value, and let the contents of the else blocks be executed each time, except, of course, for the part in which the evaluation value is stored.

By the way, here is a dump of the var_export() array after sorting it:

 array ( 0 => array ( 'countries' => 'EN,SP,FR', '_score' => 25, ), 1 => array ( 'countries' => 'EN,DE,SP', '_score' => 23, ), 2 => array ( 'countries' => 'EN,CH,SP', '_score' => 21, ), 3 => array ( 'countries' => 'CH,EN,SP', '_score' => 21, ), 4 => array ( 'countries' => 'DE,SP,CH', '_score' => 16, ), 5 => array ( 'countries' => 'DE,FR,CH', '_score' => 15, ), 6 => array ( 'countries' => 'DE,SV,SP', '_score' => 14, ), ) 

Enjoy it!

+12
Jan 13 '10 at 18:50
source share

Finally found this wonderful feature on PHP.net:

  function array_msort($array, $cols) { $colarr = array(); foreach ($cols as $col => $order) { $colarr[$col] = array(); foreach ($array as $k => $row) { $colarr[$col]['_'.$k] = strtolower($row[$col]); } } $eval = 'array_multisort('; foreach ($cols as $col => $order) { $eval .= '$colarr[\''.$col.'\'],'.$order.','; } $eval = substr($eval,0,-1).');'; eval($eval); $ret = array(); foreach ($colarr as $col => $arr) { foreach ($arr as $k => $v) { $k = substr($k,1); if (!isset($ret[$k])) $ret[$k] = $array[$k]; $ret[$k][$col] = $array[$k][$col]; } } return $ret; } 

Here's what each country looks like: $ array ['countries'] = in_array ($ needle, $ haystack); }

 $array = $array = array_msort($array, array('countries'=>SORT_DESC, 'id'=>SORT_ASC)); 

Thank you all for your help!

+2
Jan 13 '10 at 22:30
source share

You can consider array_walk and array_walk_recursive and array_map , which when combined can possibly do what you want to do.

+1
Jan 13
source share
0
Jan 13
source share

Take a look at uasort to learn how to use a custom comparison function.

0
Jan 13 '10 at 18:52
source share



All Articles