Sorting a Multi-Dimensional Array with PHP

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.

103 Replies to “Sorting a Multi-Dimensional Array with PHP”

  1. 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.

  2. 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.

  3. Why not just do:

    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;
    }
    

    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

  4. 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()?

  5. 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.

  6. 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.

  7. 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! =)

  8. 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.

  9. 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 —

  10. just a thought you could extend off your function and choose how to sort your array like so:

    function subval_sort($a,$subkey,$sort) {
    	foreach($a as $k=>$v) {
    		$b[$k] = strtolower($v[$subkey]);
    	}
    	$sort($b);
    	foreach($b as $key=>$val) {
    		$c[] = $a[$key];
    	}
    	return $c;
    }
    
    $songs = subval_sort($songs,'artist',arsort); 
    print_r($songs);
    
    
  11. This is indeed good script to sort a multidimensional array. Thnxs for your contribution…

  12. 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

  13. 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.

  14. I'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?

  15. Pingback: Omkar's Lab
  16. 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,

  17. 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.

    function subval_sort($a,$subkey) {
    	foreach($a as $k=>$v) {
    		$b[$k] = $v[$subkey];
    	}
    	asort($b);
    	foreach($b as $key=>$val) {
    		$c[$key] = $a[$key];
    	}
    	return $c;
    } // End of subval_sort
    
    1. 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.

      1. 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.

  18. Thanks a million sorting a multi-dimensional array was a total head wreck for me until i discovered this script…. good karma to you!

  19. 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 🙂

  20. 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?

    1. 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 [email protected]

  21. 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!

  22. 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!

  23. I know you mentioned usort() but callbacks, while a bit more complicated than procedural PHP make the solution to this much easier!

    function compare($a, $b)
    {
        return ($a['artist'] > $b['artist']);
    }
    usort($songs, "compare");

    Much better than unnecessary looping & sorting in my opinion.

    1. 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.

  24. Is there any way to make list simpler? This is what i use for sorting my multi arrays


    function mdsort($array, $sort, $sorttype)
    {
    $listing=array();
    foreach($array as $key => $value)
    {
    $listing[$key]=$value[$sort];
    }
    $sorttype($listing);
    $keylisting=array();
    foreach($listing as $key => $value)
    {
    $keylisting[]=$key;
    }
    return $keylisting;
    }
    $ylist=mdsort($mainlist, name, asort);

  25. Perhaps superfluous, but If your keys are integers, use asort($b, SORT_NUMERIC) in the function. Then you get:


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

    $sorted = subval_sort($modulestats, 'module');
    print_r($sorted);
    Array (
    [0] => Array ( [module] => 6 [received] => 994 )
    [1] => Array ( [module] => 14 [received] => 908 )
    [2] => Array ( [module] => 15 [received] => 897 )
    )

  26. 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] 😛

  27. 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!

  28. 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!


    function subval_sort( $a, $subkey, $order='asc' ) {
    foreach( $a as $k=>$v )
    $b[$k] = strtolower( $v[$subkey] );
    if( $order === 'dec' )
    arsort( $b );
    else
    asort( $b );
    foreach( $b as $key=>$val )
    $c[$key] = $a[$key];
    return $c;
    }

  29. 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.

  30. 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

  31. 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=>$v )
    $b[$k] = strtolower( $v[$subkey] );
    if( $order === ‘desc’ )
    arsort( $b );
    else
    asort( $b );
    foreach( $b as $k=>$v )
    $c[] = $a[$k];
    return $c;
    }

    $albums = subval_sort($albums,’name’, ‘asc’);

  32. 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.

  33. Your function seems to have changed the Pumpkins song from “Soma” to “Cherub Rock”. Better start debugging 😉

  34. 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:

    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;
    }
    
  35. 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.

  36. 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!

  37. Thank you so much. This is exactly what I needed and it saved me the headache of figuring out my own function.

  38. Thanks for your solution.
    I have a multi-dimension array have “date” element
    Do you know how to sort by “date”?

    1. [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]

  39. $seriesunique=subval_sort(super_unique($itemarray,’series2′),’series2′);
    function super_unique($array,$key) // Function for Unique Arrays
    {
    $temp_array = array();
    foreach ($array as &$v) {
    if (!isset($temp_array[$v[$key]]))
    $temp_array[$v[$key]] =& $v;

    }

    $array = array_values($temp_array);
    return $array;
    }
    function subval_sort($a,$subkey) { // Function for Alphasorting
    foreach($a as $k=>$v) {
    $b[$k] = strtolower($v[$subkey]);
    }
    asort($b);
    foreach($b as $key=>$val) {
    $c[] = $a[$key];
    }
    return $c;
    }

  40. 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”);

  41. 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.

  42. I saw PHP Sort Array By SubArray Value but it didn’t help much. Any ideas how to do this?

  43. Thank you very much for these wonderful tutorials! I am a huge fan of yours since 2011 and still is…

Comments are closed.