0

I have an array being created which contains a date:

$arr = array();
$arr["one"][] = array(
    'due' => '17-01-2021 10:00:00',
);
$arr["one"][] = array(
    'due' => '17-01-2021 09:00:00',
);
$arr["two"][] = array(
    'due' => '19-01-2021 09:00:00',
);
$arr["two"][] = array(
    'due' => '18-01-2021 09:00:00',
);

And I want to order by the value of the 'due' key

I tried adding this uasort function:

uasort($arr, function ($a, $b) {
    return $a["due"] <=> $b["due"];
});

print_r($arr);

But that still shows in the order above, whereas it should be showing the '09:00:00' value first

13
  • I'm not aware of any way you can do this using the uasort function, surely it'd be easier for you to create a loop, or is this an issue for performance? Commented Jan 17, 2021 at 14:04
  • 1
    A couple of issues - your data is in $arr["one"], so use this as the array to sort, and both sides of your test are $b["due"] Commented Jan 17, 2021 at 14:07
  • @NigelRen I do have more keys than just "one", so i used $ret Commented Jan 17, 2021 at 14:09
  • If your data is more complex than this, then you would need to show a short example to clarify this, but hopefully the idea may help. Commented Jan 17, 2021 at 14:10
  • 1
    One thing to be very careful of is that you are comparing strings and (it sounds as though) you want it in date/time order. Commented Jan 17, 2021 at 14:14

1 Answer 1

1

Your approach wasn't really that far off, I basically just changed a few little things:

  1. Loop over each "word-number-indexed" array individually (those indexed under one and two in the main array $arr).
  2. Convert the due dates/times to unix timestamps to have an integer that can be compared. Without this, PHP tries to sort the strings on a character-by-character basis which does not work with your format but would work if your format was YYYY-MM-DD hh:mm:ss (because the "biggest" position value would be at the start).
  3. Use usort instead of uasort since there is no point in keeping the keys (which are integers to begin with and neither one nor due in this context.
$arr = array();
$arr["one"][] = array(
    'due' => '17-01-2021 10:00:00',
);
$arr["one"][] = array(
    'due' => '17-01-2021 09:00:00',
);
$arr["two"][] = array(
    'due' => '19-01-2021 09:00:00',
);
$arr["two"][] = array(
    'due' => '18-01-2021 09:00:00',
);


foreach ($arr as &$numberIndex) {
    usort($numberIndex, function ($a, $b) {
        return strtotime($a["due"]) <=> strtotime($b["due"]);
    });
}

print_r($arr);

Some side notes:

  • Note the & at &$numberIndex, without this PHP works on an in-place copy of your value and it is never changed in $arr.
  • This approach with strototime() only works if all your dates/times are after epoch time 0 (which is 1st of January 1970). If you need to use older dates you can create DateTime() objects within the sort callback.

The resulting array looks like this:

Array
(
    [one] => Array
        (
            [0] => Array
                (
                    [due] => 17-01-2021 09:00:00
                )

            [1] => Array
                (
                    [due] => 17-01-2021 10:00:00
                )

        )

    [two] => Array
        (
            [0] => Array
                (
                    [due] => 18-01-2021 09:00:00
                )

            [1] => Array
                (
                    [due] => 19-01-2021 09:00:00
                )

        )

)
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.