php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #68622 Function to sort an array by a particular key
Submitted: 2014-12-18 15:49 UTC Modified: 2014-12-29 10:44 UTC
From: craig at craigfrancis dot co dot uk Assigned: levim (profile)
Status: Not a bug Package: Arrays related
PHP Version: Irrelevant OS:
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: craig at craigfrancis dot co dot uk
New email:
PHP Version: OS:

 

 [2014-12-18 15:49 UTC] craig at craigfrancis dot co dot uk
Description:
------------
As hinted by example 3:

	http://php.net/array_multisort

I find that I'm frequently sorting arrays by a particular key (admittedly not from the database, as that has the ORDER BY clause).

This can be done with:

	function sort_name($a, $b) {
		return strnatcmp($a['name'], $b['name']);
	}
	uasort($data, 'sort_name');

Or perhaps with PHP 5.3 anonymous functions:

	uasort($data, function ($a, $b) {
			return strnatcmp($a['name'], $b['name']);
		});

But perhaps we could introduce a function that can reduce the amount of code required (making it easier to read):

	array_key_sort($data, 'name');

	array_key_sort($data, 'name', SORT_STRING);

The example implementation below uses a class, as unfortunately my code needs to run on a PHP 5.1 server (so no anonymous functions).

Test script:
---------------
	function array_key_sort(&$array, $key, $type = 'numerical') {
		$array_key_sort = new array_key_sort($key);
		uasort($array, array($array_key_sort, $type));
	}
	class array_key_sort {
		private $key = NULL;
		public function __construct($key) {
			$this->key = $key;
		}
		public function numerical($a, $b) {
			if ($a[$this->key] == $b[$this->key]) {
				return 0;
			}
			return ($a[$this->key] < $b[$this->key] ? -1 : 1);
		}
		public function strcmp($a, $b) {
			return strcmp($a[$this->key], $b[$this->key]);
		}
		public function strcasecmp($a, $b) {
			return strcasecmp($a[$this->key], $b[$this->key]);
		}
		public function strnatcmp($a, $b) {
			return strnatcmp($a[$this->key], $b[$this->key]);
		}
		public function strnatcasecmp($a, $b) {
			return strnatcasecmp($a[$this->key], $b[$this->key]);
		}
	}


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2014-12-28 18:00 UTC] levim@php.net
-Status: Open +Status: Not a bug -Assigned To: +Assigned To: levim
 [2014-12-28 18:00 UTC] levim@php.net
I can generalize this pattern into two functions; here is an example:

<?php

$f  = function(callable $select, callable $f) {
    return function(...$args) use($select, $f) {
        return $f(...array_map($f, $args));
    };
};

function select_offset($offset) {
    return function($data) {
        return $data[$offset];
    };
}

$array = [
    ['name' => 'Bob'],
    ['name' => 'Bird'],
];

uasort($array, $f('strnatcmp', select_offset('name')));

var_dump($array);

?>

However, I genuinely think that writing it out explicitly is better:

<?php
uasort($array, function($a, $b) {
    return strnatcmp($a['name'], $b['name']);
});
?>

Also note that any function we add won't help you on a PHP 5.1 system since it would not be backported.
 [2014-12-28 18:07 UTC] levim@php.net
Here is a working example (PHP 5.3+) of what I posted in the last comment:

<?php

$f = function($f, $select) {
    return function() use($f, $select) {
        return call_user_func_array(
            $f,
            array_map($select, func_get_args())
        );
    };
};

function select_offset($offset) {
    return function($data) use($offset) {
        return $data[$offset];
    };
}

$array = array(
    array('name' => 'Bob'),
    array('name' => 'Bird'),
);

uasort($array, $f('strnatcmp', select_offset('name')));

var_dump($array);

?>
 [2014-12-29 10:44 UTC] craig at craigfrancis dot co dot uk
Fair enough... I just thought that this was a pretty common use case that it might be better to have a function that everyone could use.

Says he remembering that I should have used the SORT_NUMERIC/NATURAL/STRING/REGULAR constants, as the function names are not particularly easy to remember (e.g. strnatcasecmp).

--------------------------------------------------

<?php

	function array_key_sort(&$array, $key, $sort_flags = SORT_STRING, $sort_order = SORT_ASC) {
		$array_key_sort = new array_key_sort($key);
		switch ($sort_flags & ~SORT_FLAG_CASE) { // ref https://github.com/php/php-src/blob/master/ext/standard/array.c#L144
			case SORT_NUMERIC:
				$type = 'numeric';
				break;
			case SORT_NATURAL:
				$type = ($sort_flags & SORT_FLAG_CASE ? 'strnatcasecmp' : 'strnatcmp');
				break;
			case SORT_STRING:
			case SORT_REGULAR:
			default:
				$type = ($sort_flags & SORT_FLAG_CASE ? 'strcasecmp' : 'strcmp');
				break;
		}
		uasort($array, array($array_key_sort, $type));
		if ($sort_order == SORT_DESC) { // Cannot merge type and order
			$array = array_reverse($array);
		}
	}

		if (!defined('SORT_NATURAL')) define('SORT_NATURAL', 6); // PHP 5.4+
		if (!defined('SORT_FLAG_CASE')) define('SORT_FLAG_CASE', 8);

		class array_key_sort {
			private $key = NULL;
			public function __construct($key) {
				$this->key = $key;
			}
			public function strcmp($a, $b) {
				return strcmp($a[$this->key], $b[$this->key]);
			}
			public function strcasecmp($a, $b) {
				return strcasecmp($a[$this->key], $b[$this->key]);
			}
			public function strnatcmp($a, $b) {
				return strnatcmp($a[$this->key], $b[$this->key]);
			}
			public function strnatcasecmp($a, $b) {
				return strnatcasecmp($a[$this->key], $b[$this->key]);
			}
			public function numeric($a, $b) {
				if ($a[$this->key] == $b[$this->key]) {
					return 0;
				}
				return ($a[$this->key] < $b[$this->key] ? -1 : 1);
			}
		}

?>

e.g.
  array_key_sort($results, 'score', SORT_NUMERIC, SORT_DESC);
  array_key_sort($products, 'sort', SORT_NUMERIC);
 
PHP Copyright © 2001-2025 The PHP Group
All rights reserved.
Last updated: Tue Jul 01 14:01:37 2025 UTC