0

I have seen other examples, such as:

PHP Sort Array By SubArray Value

The responses there were great, and I expect to incorporate the sortBySubValue part of the solution proposed by @Pigalev Pavel.

In my use case though, I have an extra level of sub-array, and when I pass in my array, it does not get sorted...

My array structure is:

$players = array(
    array(
        "name" => "Woods",
        "countback" => array(
            "9" => 17,
            "6" => 11,
            "3" => 6,
            "1" => 2
        )
    ),
    array(
        "name" => "Spieth",
        "countback" => array(
            "9" => 17,
            "6" => 12,
            "3" => 4,
            "1" => 2
        )
    ),
    array(
        "name" => "McIlroy",
        "countback" => array(
            "9" => 17,
            "6" => 12,
            "3" => 5,
            "1" => 1
        )
    ),
    array(
        "name" => "Johnson",
        "countback" => array(
            "9" => 17,
            "6" => 12,
            "3" => 5,
            "1" => 2
        )
    )
);

Where the parent array is sorted by the order of the countback sub-array. The expected final order should be:

  1. Johnson, winner because the 4th array value (2) is highest in final comparison
  2. McIlroy, 2nd as the 4th array value (1) is lower
  3. Speech, 3rd as the 3rd array value (4) is lower than the remainders
  4. Woods, lowest as 2nd array value (11) is lower than the others.

What changes need to be made to the function provided by @Pigalev Pavel?

/**
 * @param array $array
 * @param string $value
 * @param bool $asc - ASC (true) or DESC (false) sorting
 * @param bool $preserveKeys
 * @return array
 * */
function sortBySubValue($array, $value, $asc = true, $preserveKeys = false)
{
    if (is_object(reset($array))) {
        $preserveKeys ? uasort($array, function ($a, $b) use ($value, $asc) {
            return $a->{$value} == $b->{$value} ? 0 : ($a->{$value} <=> $b->{$value}) * ($asc ? 1 : -1);
        }) : usort($array, function ($a, $b) use ($value, $asc) {
            return $a->{$value} == $b->{$value} ? 0 : ($a->{$value} <=> $b->{$value}) * ($asc ? 1 : -1);
        });
    } else {
        $preserveKeys ? uasort($array, function ($a, $b) use ($value, $asc) {
            return $a[$value] == $b[$value] ? 0 : ($a[$value] <=> $b[$value]) * ($asc ? 1 : -1);
        }) : usort($array, function ($a, $b) use ($value, $asc) {
            return $a[$value] == $b[$value] ? 0 : ($a[$value] <=> $b[$value]) * ($asc ? 1 : -1);
        });
    }
    return $array;
}

If I print_r($players); at the end of my PHP script, the array remains in the original order.

UPDATE & RESOLVED Following comments provided, the issue was that I have printed the original array ($players), without allowing the function to update the original variable (by reference). the other option is to store it in a new variable returned by the function itself, as:

$sortedPlayers = sortBySubValue($players, 'countback', false);

jingo_man
  • 509
  • 3
  • 13
  • how you're calling this function? I've just tried and it's working for me and getting expected result `sortBySubValue($players, 'countback', false);` – Haridarshan May 15 '21 at 10:35
  • @Haridarshan Not seeing it: https://3v4l.org/QMdEe – El_Vanja May 15 '21 at 10:49
  • 1
    @El_Vanja, that's because `$players` passed to `sortBySubValue` is not passed by reference, so the array is not changing - https://3v4l.org/CiSTH – Haridarshan May 15 '21 at 11:00
  • @Haridarshan Ah, my bad, hadn't noticed the return. – El_Vanja May 15 '21 at 11:19
  • I have tried a few combinations: `sortBySubValue($players,'countback', false);`, `sortBySubValue($players,'countback', true);`, `sortBySubValue($players,'countback', false, false);`, `sortBySubValue($players,'countback', true, true);` – jingo_man May 15 '21 at 12:47
  • @Haridarshan - what is the "by reference" part? – jingo_man May 15 '21 at 12:49
  • 1
    @jingo_man TL;DR **Pass by reference** means passing the reference/address of the argument to the function and that is done by using `&` in function argument. If you'll check this - https://3v4l.org/CiSTH, the first argument `$array` of the function is changed to `&$array`. If you we don't want to make this change then we just need to use the returned array i.e. `$players = sortBySubValue($players, 'countback', false);` – Haridarshan May 15 '21 at 13:05
  • I call it like `sortBySubValue($players, "countback", false);` and get the desired result (order: Johnson, McIlroy, Speech, Woods). I think asc parameter is on the contrary. – nachospiu May 15 '21 at 13:26
  • Thanks for all the assistance & explanations. Indeed, I initially used `print_r($players);`, just an honest mistake of usage. If I assign the function call to a new var or use the `&` by reference, it works as expected. – jingo_man May 16 '21 at 17:01

0 Answers0