Reputation: 899
I am aware of the fact that I can usort an array by one column using something like this:
function cmp($a, $b)
{
return $b['column'] - $a['column'];
}
usort($array, "cmp");
This simulates the ORDER BY column DESC
.
What if I want to simulate the ORDER BY column1 DESC, column2 ASC
or ORDER BY column1, column2 DESC
or also by more columns? Is it possible with PHP or it's pretty much a work that just SQL can do? Thanks.
Upvotes: 4
Views: 658
Reputation: 9052
You can use usort
which provides a callback function which expects -1
(or less), 0
or 1
(or more) to know whether the item should be moved back, remain in the same position or move up.
$data = [
["name" => "Jack", "description" => "One big tool", "qty" => 13],
["name" => "Drill", "description" => "One small tool", "qty" => 2],
["name" => "Hammer", "description" => "Just the right tool", "qty" => 8],
["name" => "Screw Driver", "description" => "Making holes", "qty" => 1],
["name" => "Hammer", "description" => "A different tool", "qty" => 1],
];
// Sort by name, then description and then qty
usort($data, function ($a, $b) {
// ASC when you put $a first and $b second, swop around for DESC
$name_sort = strcmp($a["name"], $b["name"]);
// if name_sort is 0 the values are the same, then sort by description
if ($name_sort !== 0) {
return $name_sort;
}
$description_sort = strcmp($a["description"], $b["description"]);
// if description_sort is 0, then sort by qty
if ($description_sort !== 0) {
return $description_sort;
}
// name and description values are the same, sort by qty
return intval($a["qty"]) - intval($b["qty"]);
});
For Object-Orientated PHP:
/** @var MyObj[] $data */
$data = [
new MyObj("Jack", "One big tool", 13),
new MyObj("Drill", "One small tool", 2),
new MyObj("Hammer", "Just the right tool", 8),
new MyObj("Screw Driver", "Making holes", 1),
new MyObj("Hammer", "A different tool", 1),
];
usort($data, function (MyObj $a, MyObj $b) {
$name_sort = strcmp($a->name, $b->name);
if ($name_sort !== 0) {
return $name_sort;
}
$description_sort = strcmp($a->description, $b->description);
if ($description_sort !== 0) {
return $description_sort;
}
return $a->qty - $b->qty;
});
The MyObj
class is as follows:
class MyObj
{
public string $name;
public string $description;
public int $qty;
public function __construct(
string $name,
string $description,
int $qty
) {
$this->name = $name;
$this->description = $description;
$this->qty = $qty;
}
}
Upvotes: 0
Reputation: 1712
You can do using foreach loop, $data sorting.
<?php
$data[] = array('volume' => 67, 'edition' => 2);
$data[] = array('volume' => 86, 'edition' => 1);
$data[] = array('volume' => 85, 'edition' => 6);
$data[] = array('volume' => 98, 'edition' => 2);
$data[] = array('volume' => 86, 'edition' => 6);
$data[] = array('volume' => 67, 'edition' => 7);
// Obtain a list of columns
foreach ($data as $key => $row) {
$volume[$key] = $row['volume'];
$edition[$key] = $row['edition'];
}
// Sort the data with volume descending, edition ascending
// Add $data as the last parameter, to sort by the common key
array_multisort($volume, SORT_DESC, $edition, SORT_ASC, $data);
var_dump($data);
Working DEMO
Upvotes: 0
Reputation: 2136
It's easy. Sorting by multiple columns means that you just use another sort criterium if the first sort criterium is equal:
function cmp($a, $b)
{
if ($a['col1'] !== $b['col1']) {
return $b['col1'] - $a['col1'];
}
return $a['col2'] - $b['col2'];
}
usort($array, 'cmp');
this is the same like ORDER BY col1 DESC, col2 ASC
While it seems some bit more code than the multisort it is much more flexible. Depends if you want to calculate something inside. For example: sort by the length of a column.
Upvotes: 1
Reputation: 11642
I believe you mean array-multisort
array_multisort — Sort multiple or multi-dimensional arrays
Simple example:
$data[] = array('volume' => 67, 'edition' => 2);
$data[] = array('volume' => 86, 'edition' => 1);
$data[] = array('volume' => 85, 'edition' => 6);
$data[] = array('volume' => 98, 'edition' => 2);
$data[] = array('volume' => 86, 'edition' => 6);
$data[] = array('volume' => 67, 'edition' => 7);
array_multisort(array_column($data, 'volume'), SORT_DESC, array_column($data, 'edition'), SORT_ASC, $data);
This will make $data
sort first by volume field in DESC and then by edition field in ASC.
Upvotes: 3