0

I have the following bidimensional indexed array of multiple one-dimensional associative arrays:

Array (
    [0] => Array (
            [from] => Person 1
            [to] => Person 2
            [platform] => Instagram Direct Messaging
            [date] => 2016/06/27
            [time] => 12:00
            [ampm] => PM
            [specialcontent] => none
            [content] => Hello
     )
    [1] => Array (
            [from] => Person 1
            [to] => Person 2
            [platform] => Instagram Direct Messaging
            [date] => 2016/06/27
            [time] => 12:00
            [ampm] => PM
            [specialcontent] => none
            [content] => How are you?
     )
    [2] => Array (
            [from] => Person 2
            [to] => Person 1
            [platform] => Instagram Direct Messaging
            [date] => 2016/06/27
            [time] => 6:00
            [ampm] => PM
            [specialcontent] => none
            [content] => Oh, hey there. I'm fine
     )
    [3] => Array (
            [from] => Person 2
            [to] => Person 1
            [platform] => Instagram Direct Messaging
            [date] => 2016/06/27
            [time] => 6:01
            [ampm] => PM
            [specialcontent] => none
            [content] => What about you?
     )
)

I'd like to sort the inner arrays by the value of the date field (key) in them, which means, I have to order them by year, then by month, and then by day, in an ascending order. I can get such values from the date (key) using the following commands, respectively: $year = substr($item['date'], 0, 4);, $month = substr($item['date'], 5, 2);, $day = substr($item['date'], -2);. I also know I perhaps need to use a function like usort or array_multisort, but I can't think of how to create a function that returns the order of the arrays by the year, then month, then day of their date keys.

alejnavab
  • 1,136
  • 1
  • 12
  • 30
  • BTW they are already ordered in my code. Let's suppose they are unordered. – alejnavab Aug 04 '18 at 15:22
  • 1
    doesn't it work? `usort($arr, function ($a, $b) { return $a['date'] <=> $b['date']; });` – Nikita U. Aug 04 '18 at 15:24
  • @AntoineB I think it is a duplicate if Nikita U.'s comment works, which I will test right now. I'll then comment the results. – alejnavab Aug 04 '18 at 16:27
  • @NikitaU. I don't know how PHP could do it, but it worked. So, should I delete this question? I already got the answer (thanks to you) but no-one has answered. Perhaps you can answer with that comment and I select your answer. – alejnavab Aug 04 '18 at 16:48
  • @Machavity This wasn't quite the same question as the one you said this was a duplicate of. – alejnavab Aug 05 '18 at 02:11

3 Answers3

1

You can use usort this way:

function date_sort($a,$b){
    list($a_year,$a_month,$a_day)=explode('/',$a);
    list($b_year,$b_month,$b_day)=explode('/',$b);
    if($a_year>$b_year) return 1;
    if($a_year<$b_year) return -1;
    if($a_month>$b_month) return 1;
    if($a_month<$b_month) return -1;
    if($a_day>$b_day) return 1;
    if($a_day<$b_day) return -1;
    return 0;
}

function time_sort($a,$b){
    list($a_hour,$a_min)=explode(':',$a);
    list($b_hour,$b_min)=explode(':',$b);
    if($a_hour>$b_hour) return 1;
    if($a_hour<$b_hour) return -1;
    if($a_min>$b_min) return 1;
    if($a_min<$b_min) return -1;
    return 0;
}

function ampm_sort($a,$b){
    if($a[0]===$b[0]) return 0;
    if(strtolower($a[0])==='a'&&strtolower($b[0])==='p') return -1;
    else return 1;
}

function customSort($a,$b){
    if(date_sort($a['date'],$b['date'])>0){
        return 1;

    }elseif(date_sort($a['date'],$b['date'])<0){
        return -1;

    }else{
        if(ampm_sort($a['ampm'],$b['ampm'])>0)
            return 1;
        if(ampm_sort($a['ampm'],$b['ampm'])<0)
            return -1;
        if(ampm_sort($a['ampm'],$b['ampm'])===0){
            if(time_sort($a['time'],$b['time'])>0){
                return 1;
            }elseif(time_sort($a['time'],$b['time'])<0){
                return -1;
            }else{
                return 0;
            }
        }
    }


}

if we suppose you call your array $my_array ,you can then sort it with:

usort($my_array,'customSort');

This way you simply sort your array first by year ,then by month ,then by day ,then by time ,then by the moment of the day.

Elementary
  • 1,443
  • 1
  • 7
  • 17
  • @alej27 i think you could need this too for if you only sort by date your array it will not really be sorted because you may also need to sort by time and moment too if your try to make something like a chat... – Elementary Aug 04 '18 at 17:08
  • Thank you too for also sorting by time (including the am/pm tag)! – alejnavab Aug 04 '18 at 17:31
1

A perhaps simpler implementation, also using usort, but leveraging the function strtotime - we concatonate all our date/time fields together, convert them into unix timestamps and sort ascending.

usort($my_array, function($a, $b) {
    $a = strtotime("{$a['date']} {$a['time']} {$a['ampm']}");
    $b = strtotime("{$b['date']} {$b['time']} {$b['ampm']}");

    if($a == $b) {
        return 0;
    }

    return $a < $b ? -1 : 1;
});
Scoots
  • 3,048
  • 2
  • 21
  • 33
  • God bless you, my friend. My real intention was to also sort the messages by date, but also then by time (including the am/pm tag), which mean't I needed to sort the array by three criteria/keys. But you've already done it, and I've already tested it, and works fine! So thank **you**! – alejnavab Aug 04 '18 at 17:29
0

@Nikita's comment in the question works. In the following code, I also considered sorting the messages by time (including the AM/PM tag):

        // Sort messages by date
            usort($MessagesArray, function ($a, $b) {
                return $a['date'] <=> $b['date'];
            });
        // Sort messages by date and time
            // Obtain a list of columns
            foreach ($MessagesArray as $key => $row) {
                $date[$key]  = $row['date'];
                $time[$key] = $row['time'];
            }
            // Sort the messages
            array_multisort($date, SORT_ASC, $time, SORT_ASC, $MessagesArray);

Keep in mind @Scoots' and @Elementary's comments also already sort them by date.

alejnavab
  • 1,136
  • 1
  • 12
  • 30