How to Sort Arrays and Data in PHP

How can I sort arrays and data in PHP?

Basic one dimensional arrays

$array = array(3, 5, 2, 8);

Applicable sort functions:

  • sort
  • rsort
  • asort
  • arsort
  • natsort
  • natcasesort
  • ksort
  • krsort

The difference between those is merely whether key-value associations are kept (the "a" functions), whether it sorts low-to-high or reverse ("r"), whether it sorts values or keys ("k") and how it compares values ("nat" vs. normal). See http://php.net/manual/en/array.sorting.php for an overview and links to further details.

Multi dimensional arrays, including arrays of objects

$array = array(
array('foo' => 'bar', 'baz' => 42),
array('foo' => ..., 'baz' => ...),
...
);

If you want to sort $array by the key 'foo' of each entry, you need a custom comparison function. The above sort and related functions work on simple values that they know how to compare and sort. PHP does not simply "know" what to do with a complex value like array('foo' => 'bar', 'baz' => 42) though; so you need to tell it.

To do that, you need to create a comparison function. That function takes two elements and must return 0 if these elements are considered equal, a value lower than 0 if the first value is lower and a value higher than 0 if the first value is higher. That's all that's needed:

function cmp(array $a, array $b) {
if ($a['foo'] < $b['foo']) {
return -1;
} else if ($a['foo'] > $b['foo']) {
return 1;
} else {
return 0;
}
}

Often, you will want to use an anonymous function as the callback. If you want to use a method or static method, see the other ways of specifying a callback in PHP.

You then use one of these functions:

  • usort
  • uasort
  • uksort

Again, they only differ in whether they keep key-value associations and sort by values or keys. Read their documentation for details.

Example usage:

usort($array, 'cmp');

usort will take two items from the array and call your cmp function with them. So cmp() will be called with $a as array('foo' => 'bar', 'baz' => 42) and $b as another array('foo' => ..., 'baz' => ...). The function then returns to usort which of the values was larger or whether they were equal. usort repeats this process passing different values for $a and $b until the array is sorted. The cmp function will be called many times, at least as many times as there are values in $array, with different combinations of values for $a and $b every time.

To get used to this idea, try this:

function cmp($a, $b) {
echo 'cmp called with $a:', PHP_EOL;
var_dump($a);
echo 'and $b:', PHP_EOL;
var_dump($b);
}

All you did was define a custom way to compare two items, that's all you need. That works with all sorts of values.

By the way, this works on any value, the values don't have to be complex arrays. If you have a custom comparison you want to do, you can do it on a simple array of numbers too.

sort sorts by reference and does not return anything useful!

Note that the array sorts in place, you do not need to assign the return value to anything. $array = sort($array) will replace the array with true, not with a sorted array. Just sort($array); works.

Custom numeric comparisons

If you want to sort by the baz key, which is numeric, all you need to do is:

function cmp(array $a, array $b) {
return $a['baz'] - $b['baz'];
}

Thanks to The PoWEr oF MATH this returns a value < 0, 0 or > 0 depending on whether $a is lower than, equal to or larger than $b.

Note that this won't work well for float values, since they'll be reduced to an int and lose precision. Use explicit -1, 0 and 1 return values instead.

Objects

If you have an array of objects, it works the same way:

function cmp($a, $b) {
return $a->baz - $b->baz;
}

Functions

You can do anything you need inside a comparison function, including calling functions:

function cmp(array $a, array $b) {
return someFunction($a['baz']) - someFunction($b['baz']);
}

Strings

A shortcut for the first string comparison version:

function cmp(array $a, array $b) {
return strcmp($a['foo'], $b['foo']);
}

strcmp does exactly what's expected of cmp here, it returns -1, 0 or 1.

Spaceship operator

PHP 7 introduced the spaceship operator, which unifies and simplifies equal/smaller/larger than comparisons across types:

function cmp(array $a, array $b) {
return $a['foo'] <=> $b['foo'];
}

Sorting by multiple fields

If you want to sort primarily by foo, but if foo is equal for two elements sort by baz:

function cmp(array $a, array $b) {
if (($cmp = strcmp($a['foo'], $b['foo'])) !== 0) {
return $cmp;
} else {
return $a['baz'] - $b['baz'];
}
}

For those familiar, this is equivalent to an SQL query with ORDER BY foo, baz.

Also see this very neat shorthand version and how to create such a comparison function dynamically for an arbitrary number of keys.

Sorting into a manual, static order

If you want to sort elements into a "manual order" like "foo", "bar", "baz":

function cmp(array $a, array $b) {
static $order = array('foo', 'bar', 'baz');
return array_search($a['foo'], $order) - array_search($b['foo'], $order);
}

For all the above, if you're using PHP 5.3 or higher (and you really should), use anonymous functions for shorter code and to avoid having another global function floating around:

usort($array, function (array $a, array $b) { return $a['baz'] - $b['baz']; });

That's how simple sorting a complex multi-dimensional array can be. Again, just think in terms of teaching PHP how to tell which of two items is "greater"; let PHP do the actual sorting.

Also for all of the above, to switch between ascending and descending order simply swap the $a and $b arguments around. E.g.:

return $a['baz'] - $b['baz']; // ascending
return $b['baz'] - $a['baz']; // descending

Sorting one array based on another

And then there's the peculiar array_multisort, which lets you sort one array based on another:

$array1 = array( 4,   6,   1);
$array2 = array('a', 'b', 'c');

The expected result here would be:

$array2 = array('c', 'a', 'b');  // the sorted order of $array1

Use array_multisort to get there:

array_multisort($array1, $array2);

As of PHP 5.5.0 you can use array_column to extract a column from a multi dimensional array and sort the array on that column:

array_multisort(array_column($array, 'foo'), SORT_DESC, $array);

You can also sort on more than one column each in either direction:

array_multisort(array_column($array, 'foo'), SORT_DESC,
array_column($array, 'bar'), SORT_ASC,
$array);

As of PHP 7.0.0 you can also extract properties from an array of objects.



If you have more common cases, feel free to edit this answer.

How to Sort a Multi-dimensional Array by Value

Try a usort. If you are still on PHP 5.2 or earlier, you'll have to define a sorting function first:

function sortByOrder($a, $b) {
return $a['order'] - $b['order'];
}

usort($myArray, 'sortByOrder');

Starting in PHP 5.3, you can use an anonymous function:

usort($myArray, function($a, $b) {
return $a['order'] - $b['order'];
});

And finally with PHP 7 you can use the spaceship operator:

usort($myArray, function($a, $b) {
return $a['order'] <=> $b['order'];
});

To extend this to multi-dimensional sorting, reference the second/third sorting elements if the first is zero - best explained below. You can also use this for sorting on sub-elements.

usort($myArray, function($a, $b) {
$retval = $a['order'] <=> $b['order'];
if ($retval == 0) {
$retval = $a['suborder'] <=> $b['suborder'];
if ($retval == 0) {
$retval = $a['details']['subsuborder'] <=> $b['details']['subsuborder'];
}
}
return $retval;
});

If you need to retain key associations, use uasort() - see comparison of array sorting functions in the manual.

Sorting a php array of arrays by custom order

You can use usort() to dictate precisely how the array is to be sorted. In this case, the $order array can be used within the comparison function.

The example below uses a closure to make life easier.

$order = array(3452342, 5867867, 7867867, 1231233);
$array = array(
array('id' => 7867867, 'title' => 'Some Title'),
array('id' => 3452342, 'title' => 'Some Title'),
array('id' => 1231233, 'title' => 'Some Title'),
array('id' => 5867867, 'title' => 'Some Title'),
);

usort($array, function ($a, $b) use ($order) {
$pos_a = array_search($a['id'], $order);
$pos_b = array_search($b['id'], $order);
return $pos_a - $pos_b;
});

var_dump($array);

The key to this working is having the values that are being compared, be the positions of the ids within the $order array.

The comparison function works by finding the positions of the ids of two items to be compared within the $order array. If $a['id'] comes before $b['id'] in the $order array, then the return value of the function will be negative ($a is less so "floats" to the top). If $a['id'] comes after $b['id'] then the function returns a positive number ($a is greater so "sinks" down).

Finally, there is no special reason for using a closure; it's just my go-to way of writing these sorts of throwaway functions quickly. It could equally use a normal, named function.

Best way to sort an array of data in PHP

The answer to this was quite simple, Mark Baker put me on the right track.

I originally used a convoluted mix between rsort, krsort and array_flip to get an almost working solution.

Using rsort with the SORT_NATURAL flag did the trick.

PHP - Sort array by value in subarray - DESC and ASC

The answer you link to tells you exactly what you need to do, doesn't it? The only thing I would add is that you might appreciate the strnatcmp function for comparing strings rather than numbers. So you'd have:

function cmp_by_clientType($a, $b) {
return strnatcmp($a["client_type"], $b["client_type"]);
}

usort($array, "cmp_by_clientType");

When you say the answer you link to doesn't work, what is the problem you're experiencing?

EDIT

For asc and desc the simplest would be to have two sort functions, so for DESC you'd have the same function but you swap $a and $b:

function cmp_by_clientType_DESC($a, $b) {
return strnatcmp($b["client_type"], $a["client_type"]);
}

If you find this inelegant, you could maybe pass a boolean to the compare function, but that's more tricky. You can read more here:

Pass extra parameters to usort callback

Sort data in an array before displaying in a table in PHP

Checkout PHP sorting functions:

http://www.php.net/manual/en/array.sorting.php

PHP: Sort an array

try this.

<?php
$my_array = array('ben' => 1.0, 'ken' => 2.0, 'sam' => 1.5);

arsort($my_array);
print_r($my_array);
?>

The arsort() function sorts an array by the values in reverse order. The values keep their original keys.

How to sort an array of associative arrays by value of a given key in PHP?

You are right, the function you're looking for is array_multisort().

Here's an example taken straight from the manual and adapted to your case:

$price = array();
foreach ($inventory as $key => $row)
{
$price[$key] = $row['price'];
}
array_multisort($price, SORT_DESC, $inventory);

As of PHP 5.5.0 you can use array_column() instead of that foreach:

$price = array_column($inventory, 'price');

array_multisort($price, SORT_DESC, $inventory);

PHP sort array of objects by two properties

Why the extra level of indirection and making things more confusing? Why not usort directly with usort($objectArray, "sortObjects"); using a sortObjects($a,$b) function that does what any comparator does: return negative/0/positive numbers based on the input?

If the tabs differ, return their comparison, if they're the same, return the order comparison; done.

$array = array(
(object)array(
'tab_option_name_selector' => 2,
'fieldtype' => 'notes',
'order' => 12
),
(object)array(
'tab_option_name_selector' => 2,
'fieldtype' => 'notes',
'order' => 8
),
(object)array(
'tab_option_name_selector' => 1,
'order' => 2,
'fieldtype' => 'selectbox'
),
(object)array(
'tab_option_name_selector' => 2,
'order' => 3,
'fieldtype' => 'selectbox'
)
);

function compareTabAndOrder($a, $b) {
// compare the tab option value
$diff = $a->tab_option_name_selector - $b->tab_option_name_selector;
// and return it. Unless it's zero, then compare order, instead.
return ($diff !== 0) ? $diff : $a->order - $b->order;
}

usort($array, "compareTabAndOrder");
print_r($array);

Sort Array by amount of matches and put best fit first php

Not sure if this works in all cases but it gives the desired result for your current data:

<?php
$search = ['A', 'B'];

$result = [
[
'id' => 3011,
'tags' => ['A', 'B', 'C'],
],
[
'id' => 10798,
'tags' => ['A', 'C', 'D', 'E'],
],
[
'id' => 92,
'tags' => ['A'],
],
[
'id' => 4237,
'tags' => ['A', 'B'],
],
];

usort($result, function ($a, $b) use ($search) {
$simA = count(array_intersect($a['tags'], $search));
$simB = count(array_intersect($b['tags'], $search));
$diffA = count(array_diff($a['tags'], $search));
$diffB = count(array_diff($b['tags'], $search));
$absA = abs(count($a['tags']) - count($search));
$absB = abs(count($b['tags']) - count($search));

$score = 0;

$score += $simB - $simA;
$score += $diffA - $diffB;
$score += $absA - $absB;

return $score;
});

echo '<pre>';
print_r($result);
echo '</pre>';

http://phpio.net/s/7yhb



Related Topics



Leave a reply



Submit