Adam's Blog

Sorting a Multi-Dimensional Array with PHP

Adam Scheinberg, January 16, 2009 (16 years ago)

Every so often I find myself with a multidimensional array that I want to sort by a value in a sub-array. I have an array that might look like this:
//an array of some songs I like
$songs = array(
'1' => array('artist'=>'The Smashing Pumpkins', 'songname'=>'Soma'),
'2' => array('artist'=>'The Decemberists', 'songname'=>'The Island'),
'3' => array('artist'=>'Fleetwood Mac', 'songname' =>'Second-hand News')
);

The problem is thus: I'd like to echo out the songs I like in the format "Songname (Artist)," and I'd like to do it alphabetically by artist. PHP provides many functions for sorting arrays, but none will work here. ksort() will allow me to sort by key, but the keys in the $songs array are irrelevant. asort() allows me to sort and preserves keys, but it will sort $songs by the value of each element, which is also useless, since the value of each is "array()". usort() is another possible candidate and can do multi-dimensional sorting, but it involves building a callback function and is often pretty long-winded. Even the examples in the PHP docs references specific keys.
So I developed a quick function to sort by the value of a key in a sub-array. Please note this version does a case-insensitive sort. See subval_sort() below.
function subval_sort($a,$subkey) {
foreach($a as $k=>$v) {
$b[$k] = strtolower($v[$subkey]);
}
asort($b);
foreach($b as $key=>$val) {
$c[] = $a[$key];
}
return $c;
}

To use it on the above, I would simply type:

$songs = subval_sort($songs,'artist');
print_r($songs);

This is what you should expect see:

Array
(
[0] => Array
(
[artist] => Fleetwood Mac
[song] => Second-hand News
)
[1] => Array
(
[artist] => The Decemberists
[song] => The Island
)
[2] => Array
(
[artist] => The Smashing Pumpkins
[song] => Cherub Rock
)
)

The songs, sorted by artist.
Back to Blog
Ophidian
2009-01-16 16:15:52
That would work as long as no two songs have the same name.

Your best bet is likely to first divide out into multiple associative arrays (one for artist, one for song, etc...) keyed off of the row number from the main array. After that you can use array_multisort (or whatever the function is named) to get the sorting you want.
Adam S
2009-01-16 16:53:24
You're right, Ophidian, this code only works if no artist is repeated. However, array_mutisort() is for sorting the values in arrays, not for sorting them by a specific value in an array. So you will need two operations - albeit PHP built in functions. In this case, I think the function is a very quick way to specify an array and the key of a key by which to sort. I will rework it to accommodate repeat keys.
fresch
2009-01-17 05:04:55
Why not just do:
<pre>
function subval_sort($a,$subkey) {
foreach($a as $k=>$v) {
$b[$k] = strtolower($v[$subkey]);
}
asort($b);
foreach($b as $k=>$v) {
$c[] = $a[$k];
}
return $c;
}
</pre>
You basically want to sort by a value in a subarray while keeping key value association. There, it's all in that sentence. I don't get why you used the value you wanted to sort by as key and the key as value. This way you won't have problems with duplicate values.

I hope you don't use that coding style and simply did it for brevity. You must be getting hammered with PHP notices about assignment before declaration. ;-P
Adam S
2009-01-17 10:43:13
Fresch - I actually took this function, char for char, from a program that has indices that mean something and will never duplicate. I've amended the function in the post because, as a general shared function, obviously, it makes more sense this way.

As for the coding style, what, specifically, do you have a problem with? Dynamic assignment? Not saying $b = array()?
Bill, Shooter Of Bul
2009-01-19 19:23:01
I wouldn't suggest using your sort function for anything memory intensive. you create two more arrays in addition to the first! You really can't beat usort, for speed and memory without dropping down into a php extension and coding it in c.
Adam S
2009-01-25 16:25:32
Hi Bill. It's a simple function, and should definitely not be used for something that would use more than a few dozen, or maybe a few hundred, records. However, usort() is really not an elegant way to do a simple sort by the value of a specific key in an array; it's arguable that uasort() could do the above more elegantly by operating on the original array, but it requires a callback function, and in the docs, the callback is specific to the key. So if we add an argument, we're essentially building a function to do the same as the above function with *slightly* less work.

The "two arrays" it creates are destroyed on the fly, so, unless the arrays do contain a very large numbers of entries, I think it ought to safely execute quickly in PHP's memory space, which by default, if I recall, is 8MB per script.
Robbie
2009-02-16 10:27:49
This is a great little script that got me started when I couldn't wrap my head around this problem. (The paradox of programming; staying up for days on end, because you're so tired that you create bugs that need fixing)
Thanks! =)
Grumpybum
2009-05-17 00:25:35
Thank you for this code! I created a dynamically created leaderboard on my site that takes data from an xml feed for each user in the leaderboard. This allowed me to sort the leaderboard from highest score to lowest score(changed asort to arsort) without having to put the data in to a database and then read it out again.
ramener
2009-06-04 20:44:55
Thank you for this wonderful code, i've used it in my application and it run smoothly. i've modified some part to enable it to sort in reverse.

--- cheers ---
theodin
2009-06-05 05:24:00
thanks for the tutorial I have been trying to do something like this all morning!
theodin
2009-06-05 07:20:45
just a thought you could extend off your function and choose how to sort your array like so:
<pre>
function subval_sort($a,$subkey,$sort) {
foreach($a as $k=&gt;$v) {
$b[$k] = strtolower($v[$subkey]);
}
$sort($b);
foreach($b as $key=&gt;$val) {
$c[] = $a[$key];
}
return $c;
}

$songs = subval_sort($songs,'artist',arsort);
print_r($songs);

</pre>
Shoaib Latif
2009-06-18 01:56:35
This is indeed good script to sort a multidimensional array. Thnxs for your contribution...
cenneth
2009-07-20 14:24:57
thanks for the code, it helped me on the way, really nice!

just a small contribution, my case was to sort a multidimensional array and sort by filename where the names was partly aphanumerical (ie 5-9.pdf, 5-10.pdf, 5-11.pdf and so on)
using the function above the sorting was un-native; 10 comes before 2, so the result would be 4-1.pdf, 4-10.pdf, 4-2pdf.. but replace the asort($b); with natsort($b); (using native sort instead) solved the problem so 2 comes before 10.

thought it might save a few minutes for anyone with similair task.

best regards

Cenneth
brij
2009-10-12 01:37:17
Thank you for this wonderful code, i&#39;ve used it in my application and it run smoothly. i&#39;ve modified some part to enable it to sort in reverse.
Rupert
2009-11-12 16:02:37
For those who mention using this to sort in reverse order, just change<br><br>asort($b);<br><br>to<br><br>arsort($b);
Rupert
2009-11-12 16:03:26
This helped me alot, BTW. Thanks!
Christoph
2009-11-24 01:13:53
thanks a lot. great function!
Christoph
2009-11-24 01:14:10
thanks a lot. great function!
Christoph
2009-11-24 07:13:53
thanks a lot. great function!
Christoph
2009-11-24 07:14:10
thanks a lot. great function!
libeesh
2010-02-05 10:19:26
Thanks for the code , it works fine..............
rodney
2010-02-05 16:55:48
I&#39;m new to PHP and found this function... works perfectly. But now I have a multi-dimensional array that I need to sort through. Any ideas how to update function to sort by a value 3 levels down?
willowdan
2010-02-23 16:01:03
Hello .. I am very grateful I&#39;ve found this page, helped me a lot in using the right sorting script.<br><br>Many thanks
Brian
2010-04-29 16:45:00
Thanks for this! It took me about 20 seconds to get it working perfectly!
Daniel Burke
2010-05-19 16:04:05
Perfect little function! Thanks also to theodin for the added feature. I was wondering if there was such a built-in function of PHP to do this, but its not needed now! Thanks again,
mman
2010-05-21 10:40:49
Great function, I just needed to retain the association of the keys of the first array so I added the $key into line 7: $c[$key] = ... Now the keys remain the same too.
<pre>
function subval_sort($a,$subkey) {
foreach($a as $k=&gt;$v) {
$b[$k] = $v[$subkey];
}
asort($b);
foreach($b as $key=&gt;$val) {
$c[$key] = $a[$key];
}
return $c;
} // End of subval_sort
</pre>
tutoriale pc
2010-06-10 11:20:40
i see you took this function form php.net http://www.php.net/manual/en/function.asort.php#92122
it's a clever function
Adam S
2010-06-10 12:33:50
Uh... no. I wrote this function, and published it in Jan 09. Someone stole it and posted it to PHP.net, in modified form 6 months later.
kristoffe
2010-09-24 17:13:20
I modified it slightly and made it more of a visual tutorial. whomever made it first, second, third, then me, we are all helping others and I am thankful for that.

:) great work guys.
Ankush
2010-06-22 02:19:06
Thanks dude
Mile
2010-06-25 15:01:17
wow thanks.
I actually needed this for a future Mystique widget :)
Adam S
2010-06-25 15:10:29
Whoa, cool!
Ginny
2010-07-15 09:33:45
Thanks a million sorting a multi-dimensional array was a total head wreck for me until i discovered this script.... good karma to you!
Scott
2010-07-17 16:18:06
Works great! Thanks for posting this.
CJ
2010-08-16 03:48:55
Hey Adam, Thanks for posting this code. I will definitely be packaging this up and using it as a core tool for array manipulation. Been scratching my head (on and off) for a few days trying to figure this one out. Not really a programmer so this has really helped me out. Kudos points :)
billy
2010-08-26 10:56:55
Thanks very much!
any thoughts how to arrange by two subkeys?

as in arrange by artist name, and within artist name have song names arranged as well?
Tom
2010-08-30 16:21:31
Hey Billy,
I had to do a sort by two subject keys. The problem with the asort in php is it does not keep order in fields that have the same value. I rewrote a merge sort algorithm I found online to do essentially an asort (keep keys). You can use this to sort one way and then sort again another to essentially get your search by two subkeys. If you want to code shoot me an email at tomjung09@gmail.com
Mat Gilbert
2010-09-24 15:13:34
This is one of the first times EVER I have literally typed a question "php sort an array of arrays by values of the sub array" and found a simple, elegant solution the first link I clicked. Thank you!
Torpedo Press
2010-09-25 09:32:08
This is freaking cool!!!

I ran into a conflict in Wordpress between theme and plugin and had to rewrite the query - which eliminated the orderby option.

Adding a custom field to each page to sort it by was where I was headed and your little gem helped me get there.

Many, many, many thanks!
mlumaad
2010-10-28 21:45:06
This code works in my project. Thanks for this mate. :)
Dyl
2010-11-19 18:13:44
Here's a function which uses a closure to sort multi-dimensional arrays. It accepts more than one key to sort by as well.

<a href="http://www.exorithm.com/algorithm/view/sort_multi_array" rel="nofollow">http://www.exorithm.com/algorithm/view/sort_multi_array</a>
Nicolas Armstrong
2011-01-27 04:10:40
As this is using "use" this function does ONLY works for PHP &gt; 5.3.0 as anonymous functions are not available for older versions as stated there: http://www.php.net/manual/en/functions.anonymous.php

Nicolas.
Terri Ann
2010-11-30 09:40:08
I know you mentioned usort() but callbacks, while a bit more complicated than procedural PHP make the solution to this much easier!

<code><pre>function compare($a, $b)
{
return ($a['artist'] &gt; $b['artist']);
}
usort($songs, "compare");</pre></code>

Much better than unnecessary looping &amp; sorting in my opinion.
Mike Postma
2011-02-24 07:41:20
Although more elegant, usort is slower than the solution presented in the original article.
Nicolas
2011-02-25 06:01:43
In my case, usort is 9 percent faster than the original solution.
Syed Rakib Al Hasan
2012-02-08 17:05:26
i find this approach easier to the eye than the article's approach
anonymous nobody
2012-02-14 04:03:53
The downside here is you would need to have a compare function for each key and a switch block to make the sorted key selectable.
Jack B
2013-08-29 10:00:56
*thumbs up* just posted the same thing
Md. Muntasir Enam
2011-01-09 08:05:12
Thanks. Though it worked for me but I couldn't understand how it works.
Charles
2011-02-03 09:24:53
Man you are awesome.... I love this and it works fine for me...
puneet
2011-02-08 06:05:01
Thanx a lots, awesome function, realy helped me.
puneet
2011-02-08 06:05:25
Thanx a lot, awesome function, realy helped me.
Chuck
2011-02-10 14:13:04
Is there any way to make list simpler? This is what i use for sorting my multi arrays

<code>
function mdsort($array, $sort, $sorttype)
{
$listing=array();
foreach($array as $key =&gt; $value)
{
$listing[$key]=$value[$sort];
}
$sorttype($listing);
$keylisting=array();
foreach($listing as $key =&gt; $value)
{
$keylisting[]=$key;
}
return $keylisting;
}
$ylist=mdsort($mainlist, name, asort);
</code>
Ankh
2011-02-14 09:15:40
That was helpful, thanks.
Jayson
2011-02-15 10:59:56
Thank you very much so helpful!
Galactix
2011-02-22 11:02:55
Perhaps superfluous, but If your keys are integers, use asort($b, SORT_NUMERIC) in the function. Then you get:

<code>
print_r($modulestats);
Array (
[0] =&gt; Array ( [module] =&gt; 14 [received] =&gt; 908 )
[1] =&gt; Array ( [module] =&gt; 15 [received] =&gt; 897 )
[2] =&gt; Array ( [module] =&gt; 6 [received] =&gt; 994 )
)

$sorted = subval_sort($modulestats, 'module');
print_r($sorted);
Array (
[0] =&gt; Array ( [module] =&gt; 6 [received] =&gt; 994 )
[1] =&gt; Array ( [module] =&gt; 14 [received] =&gt; 908 )
[2] =&gt; Array ( [module] =&gt; 15 [received] =&gt; 897 )
)
</code>
Mauro
2011-03-10 14:16:08
I don't know how or why, but I just tried simple vanilla sort() directly on a multidimensional array, and it actually sorted it first by subarray[0] and then by subarray[1] :P
Michiel
2011-04-07 11:31:37
Great great function, tnx! Was looking for this a few years back.. If I look at my old code I see a few work-arounds which were a bit more extensive (to say the least).. :-)

Since I was fed up with it, i thought "let's look again"... and here we are, 6 lines of code... nice!
Charles Garrison
2011-04-07 12:29:29
Here is a modified version that is slightly more refined. I added the ability to sort by acceding or descending order from the function call, as well as the ability to keep the index key as suggested by Mman above... Thanks for providing this function Adam!

<code>
function subval_sort( $a, $subkey, $order='asc' ) {
foreach( $a as $k=&gt;$v )
$b[$k] = strtolower( $v[$subkey] );
if( $order === 'dec' )
arsort( $b );
else
asort( $b );
foreach( $b as $key=&gt;$val )
$c[$key] = $a[$key];
return $c;
}
</code>
Donna Okrongly
2011-05-23 19:06:10
Great! Marvelous! I was stuck, but now I'm not. Thanx a million!
DanZ
2011-06-10 01:29:45
Great script..!! absolutely help my project
thank you very much :D
Tony Hayes
2011-06-16 21:11:38
Thanks that was awesome, worked straight off the bat, I love solutions like that.
Makes me wonder why PHP doesn't have an internal function to do this, it seems like it would be such a commonly usable thing.
Sergey
2011-06-23 06:11:19
Thanks for this! I can't believe a function like this isn't a standard part of php...
Michael Ecklund
2011-07-15 13:34:09
Hello, first of all thank you for your wonderful post.

Secondly, I was wondering if it would be possible to take your function a little further...

I was looking to sort an array subkey by the order of another array. I have a user generated playlist, then all the songs are gathered. Then I need the gathered songs to be sorted by their trackName and match the order of the song titles the user entered in the Playlist Array.

I have made a post on Stack Overflow, regarding this possibility but I figured i'd make a post on here as well since you are indeed the original author of this wonderful function.

If you're curious the link to the post on Stack Overflow is located here:
http://stackoverflow.com/questions/6711548/sort-array-subkey-based-on-another-arrays-order

Otherwise, I would love to hear a response from you... :)

Thanks!

-Michael Ecklund
Mad Rog
2011-07-29 05:27:13
Very interesting, time saving and useful.

Thanks!

I added a few bits of the code together to allow for variables called the same name and sorting via asc or desc.

function subval_sort( $a, $subkey, $order) {
foreach( $a as $k=&gt;$v )
$b[$k] = strtolower( $v[$subkey] );
if( $order === 'desc' )
arsort( $b );
else
asort( $b );
foreach( $b as $k=&gt;$v )
$c[] = $a[$k];
return $c;
}

$albums = subval_sort($albums,'name', 'asc');
Marcos
2011-07-30 14:25:15
Works very well for me. Now I can sort using different index. Thanks!
Hans
2011-08-02 17:53:08
Magic. Worked beautifully - super simple, fast and easy.

Thanks for sharing.
Jon Wadsworth
2011-09-23 17:41:18
Great example. I'm glad there's others out there that are willing to post examples of simple code so others can easily port it to their project. Keep up the good work.
Erwin Nandpersad
2011-09-24 09:50:49
Thanks, very usefull!!
IDW Design
2011-09-27 19:04:42
Thanks Adam, you just helped me out of a sticky situation right there!
Ioan
Hung Nguyen
2011-11-08 13:51:33
Thanks Adam,
You're so great, your func help me alot.
Thanks again ^^
Brooks
2011-11-09 21:27:26
This just helped me tremendously... And as a fellow phish fan, I thank you.
Mike
2011-12-07 16:56:13
Your function seems to have changed the Pumpkins song from "Soma" to "Cherub Rock". Better start debugging ;-)
Adam S
2011-12-07 18:47:52
In nearly 3 years, no one - including me - has ever noticed that! Good eye!
Jeremy
2012-01-10 09:00:15
Wow lots of jerks in the comments here. This saved me the headache of trying to write it myself so thanks! I had an array of objects though so I had to make a slight change to where the values located:
<pre>
function subval_sort($a,$subkey) {
foreach($a as $k=&gt;$v) {
$b[$k] = strtolower($v-&gt;$subkey);
}
asort($b);
foreach($b as $key=&gt;$val) {
$c[] = $a[$key];
}
return $c;
}
</pre>
stefano smania
2012-02-03 17:52:23
Thank you! You helped me.
Sam
2012-02-06 00:57:13
Thankyou! Worked perfectly!
BoSua
2012-02-13 05:47:43
Thank you very much!
Raphie
2012-04-13 13:57:11
Awesome, it save me a lot of headaches!
Wes
2012-05-20 05:38:32
This is perfect, thank you!
swapna
2012-06-13 06:58:30
Thank you,It helped me alot.
Mugwomp
2012-06-15 05:16:19
Great little code snippet which I am using to sort a JSON feed from an external site - your code did exactly what I needed - thanks.
Piyush
2012-07-20 01:25:09
Hey man,
Thanks a lot its working fine...
Frankie
2012-09-02 19:29:50
Thanks for this! It is very helpful for me!
Patrick Moore
2012-10-18 16:56:02
Just wanted to say thanks for this... have been racking my brain for hours trying to sort a many-multi-dimensional array and this got me pointed in the right direction. Thanks!
kandyjet
2012-11-24 05:19:51
damn, code of the day!!! cheers!
tarik
2012-12-16 18:48:50
thank you man, really thank you :)
Justin
2013-02-28 16:36:19
Thank you so much. This is exactly what I needed and it saved me the headache of figuring out my own function.
Xem Phim
2013-06-05 10:13:18
Thanks for your solution.
I have a multi-dimension array have "date" element
Do you know how to sort by "date"?
Adam S
2013-06-05 10:33:06
[code]
function subval_sort($a,$subkey) {
foreach($a as $k=>$v) {
$b[$k] = strtolower($v[$subkey]);
}
asort($b);
foreach($b as $key=>$val) {
$c[] = $a[$key];
}
return $c;
}
$sorted = subval_sort($array,'date');
[/code]
Bart
2013-07-23 06:07:25
Works great. Simply explained. Thanks!
Emos
2013-08-23 12:37:28
$seriesunique=subval_sort(super_unique($itemarray,'series2'),'series2');
function super_unique($array,$key) // Function for Unique Arrays
{
$temp_array = array();
foreach ($array as &amp;$v) {
if (!isset($temp_array[$v[$key]]))
$temp_array[$v[$key]] =&amp; $v;

}

$array = array_values($temp_array);
return $array;
}
function subval_sort($a,$subkey) { // Function for Alphasorting
foreach($a as $k=&gt;$v) {
$b[$k] = strtolower($v[$subkey]);
}
asort($b);
foreach($b as $key=&gt;$val) {
$c[] = $a[$key];
}
return $c;
}
Jack B
2013-08-29 09:59:32
You've said that usort isn't as good but I fail to see how this isn't better than what you've done:

function cmp($a, $b){
return strcmp($a['artist'], $b['artist']);
}
usort($songs, "cmp");
Rob Haskell
2013-09-24 11:05:22
Thanks for sharing! FYI, I came across a sorting problem where certain letters were out of order in the sort column. This was resolved by adding this to the asort() function: asort($b,SORT_LOCALE_STRING); The problem is explained a http://stackoverflow.com/questions/18973064/subval-sort-is-out-of-order. Cheers
naved
2014-08-24 09:55:17
Very nice solution ... here is also a gud solution of this ... http://phpsollutions.blogspot.in/2014/08/sort-multidimentional-array-in-php.html
Anurag
2015-07-02 04:33:12
it works for me to solve my problem. Good !
Ban nha ha noi duoi 2 ty
2017-03-03 11:15:37
Not bad, but it would be very useful if there was a comparison overview. For example a table comparing the advantages/disadvantages and if it is still maintained.
Brita Jpan
2017-07-12 04:29:08
I saw PHP Sort Array By SubArray Value but it didn't help much. Any ideas how to do this?
Thuoc Diet Kien Nhat Ban
2017-11-24 05:48:14
Thank you very much for these wonderful tutorials! I am a huge fan of yours since 2011 and still is...
Back to Blog