Last active
June 8, 2020 20:35
-
-
Save amnuts/8633684 to your computer and use it in GitHub Desktop.
Sort array of objects by one or more properties of the object.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Sort an array of objects. | |
* | |
* Requires PHP 5.3+ to be installed. | |
* | |
* Will use the Intl extension to normalize characters if it's | |
* available. | |
* | |
* You can pass in one or more properties on which to sort. If a | |
* string is supplied as the sole property, or if you specify a | |
* property without a sort order then the sorting will be ascending. | |
* | |
* If the key of an array is an array, then it will sorted down to that | |
* level of node. | |
* | |
* Example usages: | |
* | |
* osort($items, 'size'); | |
* osort($items, ['size', ['time' => SORT_DESC, 'user' => SORT_ASC]]); | |
* osort($items, ['size', ['user', 'forname']]) | |
* | |
* @param array $array | |
* @param string|array $properties | |
*/ | |
function osort(&$array, $properties) | |
{ | |
if (is_string($properties)) { | |
$properties = array($properties => SORT_ASC); | |
} | |
uasort($array, function($a, $b) use ($properties) { | |
foreach($properties as $k => $v) { | |
if (is_int($k)) { | |
$k = $v; | |
$v = SORT_ASC; | |
} | |
$collapse = function($node, $props) { | |
if (is_array($props)) { | |
foreach ($props as $prop) { | |
$node = (!isset($node->$prop)) ? null : $node->$prop; | |
} | |
return $node; | |
} else { | |
return (!isset($node->$props)) ? null : $node->$props; | |
} | |
}; | |
if (class_exists('\Normalizer')) { | |
$aProp = \Normalizer::normalize($collapse($a, $k), \Normalizer::FORM_D); | |
$bProp = \Normalizer::normalize($collapse($b, $k), \Normalizer::FORM_D); | |
} else { | |
$aProp = $collapse($a, $k); | |
$bProp = $collapse($b, $k); | |
} | |
if ($aProp != $bProp) { | |
return ($v == SORT_ASC) | |
? strnatcasecmp($aProp, $bProp) | |
: strnatcasecmp($bProp, $aProp); | |
} | |
} | |
return 0; | |
}); | |
} |
Sorry, I had no idea you had posted this comment! So apologies for the delay in responding.
If you're running PHP 5.3 and above (which, really, you should be) then you can try using the Normalizer class (part of the Intl extension). I've updated the gist to include that class.
Using it is the same. Eg:
$a = [
(object)['place' => 'Deutschland', 'price' => 30],
(object)['place' => 'Italien', 'price' => 18],
(object)['place' => 'Ägypten', 'price' => 70],
(object)['place' => 'Finnland', 'price' => 120]
];
osort($a, 'place');
var_dump($a);
would result in:
array(4) {
[2] =>
class stdClass#3 (2) {
public $place =>
string(8) "Ägypten"
public $price =>
int(70)
}
[0] =>
class stdClass#1 (2) {
public $place =>
string(11) "Deutschland"
public $price =>
int(30)
}
[3] =>
class stdClass#4 (2) {
public $place =>
string(8) "Finnland"
public $price =>
int(120)
}
[1] =>
class stdClass#2 (2) {
public $place =>
string(7) "Italien"
public $price =>
int(18)
}
}
Hi
Thanks for your code.
Just, in Example usages: osort($items, array('size', array('time' => SORT_DESC, 'user' => SORT_ASC));
You miss a ) at the end ;-)
osort($items, array('size', array('time' => SORT_DESC, 'user' => SORT_ASC)));
@rodmar35 👍 Thanks for the feedback - corrected now!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi,
I'm using your function but ran into problems when trying to sort by Ä,Ö,Ü for example.
If I have the following random list of items:
Deutschland
Italien
Ägypten
Finnland
and sort it via your function ASC. Then I receive the following output:
Deutschland
Finnland
Italien
Ägypten
while the order should be:
Ägypten
Deutschland
Finnland
Italien