Search code examples
phpsortingarray-multisort

Sort multi-dimensional array by date (keys) and time (values)


Suppose the following huge array (I deliberately didn't remove any of its records so that you have a good amount of data in case someone wants to dig in and help me find a solution to my problem):

$program = array (
  '2021-07-11' => 
  array (
    0 => 
    array (
      'movie' => 'Movie 1',
      'channel' => 'Channel 10',
      'time' => '23:00',
    ),
    1 => 
    array (
      'movie' => 'Movie 2',
      'channel' => 'Channel 2',
      'time' => '01:15',
    ),
    2 => 
    array (
      'movie' => 'Movie 8',
      'channel' => 'Channel 4',
      'time' => '11:00',
    ),
    3 => 
    array (
      'movie' => 'Movie 12',
      'channel' => 'Channel 11',
      'time' => '17:30',
    ),
    4 => 
    array (
      'movie' => 'Movie 14',
      'channel' => 'Channel 5',
      'time' => '21:00',
    ),
    5 => 
    array (
      'movie' => 'Movie 15',
      'channel' => 'Channel 5',
      'time' => '02:20',
    ),
    6 => 
    array (
      'movie' => 'Movie 17',
      'channel' => 'Channel 11',
      'time' => '17:30',
    ),
    7 => 
    array (
      'movie' => 'Movie 19',
      'channel' => 'Channel 5',
      'time' => '10:00',
    ),
    8 => 
    array (
      'movie' => 'Movie 21',
      'channel' => 'Channel 8',
      'time' => '1:20',
    ),
    9 => 
    array (
      'movie' => 'Movie 33',
      'channel' => 'Channel 5',
      'time' => '00:20',
    ),
    10 => 
    array (
      'movie' => 'Movie 39',
      'channel' => 'Channel 3',
      'time' => '17:30',
    ),
    11 => 
    array (
      'movie' => 'Movie 40',
      'channel' => 'Channel 3',
      'time' => '22:00',
    ),
    12 => 
    array (
      'movie' => 'Movie 41',
      'channel' => 'Channel 5',
      'time' => '14:00',
    ),
    13 => 
    array (
      'movie' => 'Movie 42',
      'channel' => 'Channel 5',
      'time' => '23:00',
    ),
    14 => 
    array (
      'movie' => 'Movie 43',
      'channel' => 'Channel 2',
      'time' => '14:15',
    ),
    15 => 
    array (
      'movie' => 'Movie 44',
      'channel' => 'Channel 2',
      'time' => '18:00',
    ),
    16 => 
    array (
      'movie' => 'Movie 45',
      'channel' => 'Channel 2',
      'time' => '23:45',
    ),
    17 => 
    array (
      'movie' => 'Movie 46',
      'channel' => 'Channel 1',
      'time' => '22:00',
    ),
    18 => 
    array (
      'movie' => 'Movie 47',
      'channel' => 'Channel 6',
      'time' => '21:10',
    ),
  ),
  '2021-07-10' => 
  array (
    0 => 
    array (
      'movie' => 'Movie 3',
      'channel' => 'Channel 2',
      'time' => '14:15',
    ),
    1 => 
    array (
      'movie' => 'Movie 5',
      'channel' => 'Channel 3',
      'time' => '22:00',
    ),
    2 => 
    array (
      'movie' => 'Movie 6',
      'channel' => 'Channel 11',
      'time' => '23:00',
    ),
    3 => 
    array (
      'movie' => 'Movie 7',
      'channel' => 'Channel 4',
      'time' => '11:15',
    ),
    4 => 
    array (
      'movie' => 'Movie 11',
      'channel' => 'Channel 4',
      'time' => '21:00',
    ),
    5 => 
    array (
      'movie' => 'Movie 16',
      'channel' => 'Channel 2',
      'time' => '23:45',
    ),
    6 => 
    array (
      'movie' => 'Movie 20',
      'channel' => 'Channel 4',
      'time' => '23:00',
    ),
    7 => 
    array (
      'movie' => 'Movie 23',
      'channel' => 'Channel 5',
      'time' => '01:00',
    ),
    8 => 
    array (
      'movie' => 'Movie 27',
      'channel' => 'Channel 4',
      'time' => '01:00',
    ),
    9 => 
    array (
      'movie' => 'Movie 29',
      'channel' => 'Channel 7',
      'time' => '02:15',
    ),
    10 => 
    array (
      'movie' => 'Movie 31',
      'channel' => 'Channel 5',
      'time' => '14:00',
    ),
    11 => 
    array (
      'movie' => 'Movie 32',
      'channel' => 'Channel 5',
      'time' => '22:10',
    ),
    12 => 
    array (
      'movie' => 'Movie 36',
      'channel' => 'Channel 2',
      'time' => '00:01',
    ),
    13 => 
    array (
      'movie' => 'Movie 37',
      'channel' => 'Channel 2',
      'time' => '11:30',
    ),
    14 => 
    array (
      'movie' => 'Movie 38',
      'channel' => 'Channel 6',
      'time' => '22:30',
    ),
  ),
  '2021-07-09' => 
  array (
    0 => 
    array (
      'movie' => 'Movie 4',
      'channel' => 'Channel 5',
      'time' => '21:00',
    ),
    1 => 
    array (
      'movie' => 'Movie 9',
      'channel' => 'Channel 11',
      'time' => '22:00',
    ),
    2 => 
    array (
      'movie' => 'Movie 10',
      'channel' => 'Channel 9',
      'time' => '16:45',
    ),
    3 => 
    array (
      'movie' => 'Movie 18',
      'channel' => 'Channel 7',
      'time' => '22:00',
    ),
    4 => 
    array (
      'movie' => 'Movie 22',
      'channel' => 'Channel 5',
      'time' => '23:00',
    ),
    5 => 
    array (
      'movie' => 'Movie 24',
      'channel' => 'Channel 9',
      'time' => '21:00',
    ),
    6 => 
    array (
      'movie' => 'Movie 25',
      'channel' => 'Channel 9',
      'time' => '23:00',
    ),
    7 => 
    array (
      'movie' => 'Movie 26',
      'channel' => 'Channel 4',
      'time' => '21:00',
    ),
    8 => 
    array (
      'movie' => 'Movie 28',
      'channel' => 'Channel 8',
      'time' => '23:00',
    ),
    9 => 
    array (
      'movie' => 'Movie 30',
      'channel' => 'Channel 6',
      'time' => '23:45',
    ),
    10 => 
    array (
      'movie' => 'Movie 34',
      'channel' => 'Channel 3',
      'time' => '23:00',
    ),
    11 => 
    array (
      'movie' => 'Movie 35',
      'channel' => 'Channel 2',
      'time' => '22:00',
    ),
  ),
  '2021-07-12' => 
  array (
    0 => 
    array (
      'movie' => 'Movie 13',
      'channel' => 'Channel 5',
      'time' => '01:20',
    ),
  ),
)

I want to sort this array by date (the keys of the first dimension), and by the column time of the third dimension, so that I end up with a list of movies grouped by date, and sorted by their broadcast time...

The first task is a super easy one-liner...

array_multisort(array_map('strtotime', array_keys($program)), SORT_ASC, $program);

The second task however is giving me a hard time to implement in a similar elegant way... What I tried was this:

array_multisort(array_map('strtotime', array_keys($program)), SORT_ASC, array_column($program, 'time'), SORT_ASC, $program);

but this doesn't work as for some reason array_column($program, 'time') returns an empty array. In the manual it's clearly stated that the array can be A multi-dimensional array or an array of objects from which to pull a column of values from. So it can be a multi-dimensional, not a strictly two-dimensional array... Why doesn't it work in my case though? What am I missing?

What I thought was that the multi-dimensional array cannot be an associative array, so to temporarily drop the date keys, I changed the above to:

array_multisort(array_map('strtotime', array_keys($program)), SORT_ASC, array_column(array_values($program), 'time'), SORT_ASC, $program);

but unfortunately this didn't work either...

I'm struggling to do that in a smart/elegant way and avoid using a loop to go through each value, but I ran out of ideas. So any help will be very much appreciated. TIA.


Solution

  • OK, I found it!!! I needed to iterate through each sub-array (by reference) of the initial array, and perform an array_multisort in there... So the code below did the trick, and I suppose it's as elegant as it can get!!!

    array_multisort(array_map('strtotime', array_keys($program)), SORT_ASC, $program);
    
    foreach ($program as &$day) {
        array_multisort(array_column($day, 'time'), SORT_ASC, $day);
    }