Reputation: 418
Let's say I have this array:
$array = array(
array("id" => 7867867, "animal" => "Dog"),
array("id" => 3452342, "animal" => "Lion"),
array("id" => 1231233, "animal" => "Lion"),
array("id" => 5867867, "animal" => "Dog"),
array("id" => 1111111, "animal" => "Zeebra"),
array("id" => 2222222, "animal" => "Cat"),
array("id" => 3333333, "animal" => "Cat"),
array("id" => 4444444, "animal" => "Zeebra")
);
Now what I've been trying to do is use php sort functions to be able to sort it based on specific rules (not alphabetical)
The client wants this information sorted by "Lion first, Dog second, Zeebra third, Cat fourth".
Something like this:
$array = array(
array("id" => 3452342, "animal" => "Lion"),
array("id" => 1231233, "animal" => "Lion"),
array("id" => 7867867, "animal" => "Dog"),
array("id" => 5867867, "animal" => "Dog"),
array("id" => 4444444, "animal" => "Zeebra"),
array("id" => 1111111, "animal" => "Zeebra"),
array("id" => 2222222, "animal" => "Cat"),
array("id" => 3333333, "animal" => "Cat"),
);
The array would be sorted using the "animal" value and would be based on pre-determined rules.
I was trying to figure out php sort functions but I could only get those to work with sorting the arrays alphabetically or numerically.
What I've gotten to work is a block of if-statements and loops, and I would like to get rid of that slow code as soon as I can.
Upvotes: 5
Views: 3080
Reputation: 47992
PHP7 offers the "spaceship operator" to make sorting much, much simpler.
All of the following snippets will leverage a lookup array to determine the custom sorting order.
$priorities = array_flip(['Lion', 'Dog', 'Zeebra', 'Cat']);
Code: (Demo)
usort($array, function($a, $b) use ($priorities) {
return $priorities[$a['animal']] <=> $priorities[$b['animal']];
});
PHP7.4+ Code: (Demo)
usort($array, fn($a, $b) => $priorities[$a['animal']] <=> $priorities[$b['animal']]);
Your question and sample data suggest that you always have all animals acknowledged in your lookup array. If this is not always true, then you will need to make isset()
calls in your custom function and determine if you want missing animals to be placed at the front or back of the list.
Both snippets above provide the same output:
array (
0 =>
array (
'id' => 3452342,
'animal' => 'Lion',
),
1 =>
array (
'id' => 1231233,
'animal' => 'Lion',
),
2 =>
array (
'id' => 7867867,
'animal' => 'Dog',
),
3 =>
array (
'id' => 5867867,
'animal' => 'Dog',
),
4 =>
array (
'id' => 1111111,
'animal' => 'Zeebra',
),
5 =>
array (
'id' => 4444444,
'animal' => 'Zeebra',
),
6 =>
array (
'id' => 2222222,
'animal' => 'Cat',
),
7 =>
array (
'id' => 3333333,
'animal' => 'Cat',
),
)
Upvotes: 3
Reputation: 10627
Try:
function sortByAnimals($array, $animalOrderArray){
foreach($animalOrderArray as $v){
$aa[$v] = array();
}
foreach($array as $a){
foreach($aa as $i => $v){
if(preg_match("/^{$a['animal']}$/i", $i)){
array_push($aa[$i], $a);
break;
}
}
}
foreach($aa as $a){
foreach($a as $v){
$r[] = $v;
}
}
return $r;
}
$resArray = sortByAnimals($array, array('lion', 'dog', 'zeebra', 'cat'));
Upvotes: -1
Reputation: 17451
Check usort. Heres the reference:
http://www.php.net/manual/en/function.usort.php
Example:
function cmp($a, $b) {
$order=array("Lion","Dog","Zebra","Cat");
if ($a["animal"] == $b["animal"]) {
return 0;
}
return (array_search($a["animal"],$order) < array_search($b["animal"],$order)) ? -1 : 1;
}
$array = array(
array("id" => 7867867, "animal" => "Dog"),
array("id" => 3452342, "animal" => "Lion"),
array("id" => 1231233, "animal" => "Lion"),
array("id" => 5867867, "animal" => "Dog"),
array("id" => 1111111, "animal" => "Zebra"),
array("id" => 2222222, "animal" => "Cat"),
array("id" => 3333333, "animal" => "Cat"),
array("id" => 4444444, "animal" => "Zebra")
);
$mySortedArray=usort($array, "cmp");
Upvotes: 2
Reputation: 328
Using Jonathan suggestion on using usort, you can define your custom rules for sorting in a separate function, like:
function getAnimalValue($animal) {
switch($animal) {
case 'Lion':
return 1;
case 'Dog':
return 2;
case 'Zeebra':
return 3;
case 'Cat':
return 4;
}
return 0;
}
Then, implement your own compare function:
function compare($itemA, $itemB) {
$a = getAnimalValue($itemA['animal']);
$b = getAnimalValue($itemB['animal']);
if ($a == $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
}
Finally, call usort using the compare function:
usort($array, "compare");
Upvotes: 7
Reputation: 41473
This is a bit of an ugly way, but it works.
// Set our rules, the key is the order
$rules = array(0=>"Dog",1=>"Lion",2=>"Zeebra",3=>"Cat");
// Our array
$array = array(
array("id" => 7867867, "animal" => "Dog"),
array("id" => 3452342, "animal" => "Lion"),
array("id" => 1231233, "animal" => "Lion"),
array("id" => 5867867, "animal" => "Dog"),
array("id" => 1111111, "animal" => "Zeebra"),
array("id" => 2222222, "animal" => "Cat"),
array("id" => 3333333, "animal" => "Cat"),
array("id" => 4444444, "animal" => "Zeebra")
);
// Split each animal into a arrays per animal
foreach( $array as $item ){
$animals[ $item['animal'] ][] = $item;
}
// Loop our rules (dogs, then lions, etc) and put our mini arrays in a final sorted_array.
foreach( $rules as $animal_order => $animal_name ){
foreach( $animals[$animal_name] as $animal ){
$sorted_animals[] = $animal;
}
}
print_r($sorted_animals);
Upvotes: 0