Sort awkward array

I have followed the PHP & MySQL: Novice to Ninja 6 book and created a website.

I have the following code:

public function getServices($vertical_id)                                                    
  8     {
  7         $relevantServices = $this->verticalToServiceTable->find('vertical_id', $vertical_id);
  6         $services = [];
  5         foreach ($relevantServices as $verticalService) {
  4             $service = $this->servicesTable->find('service_id', $verticalService->service_id);
  3             $services[] = $service;
  2         }
  1         
  0         return $services;                                                                        
  1     }   

In vdebug, $services looks like this after the loop has finished:

$services = (array[2])
$services[0]= (array[1])
$services[0][0]
$services[0][0]->animal_id = (string [1]) '1'
$services[0][0]->animal_name = (string [8]) 'Baracuda'
$services[1]= (array[1])
$services[1][0]
$services[1][0]->animal_id = (string [1]) '2'
$services[1][0]->animal_name = (string [8]) 'Anaconda'

I’ve changed the text and, the real one is MUCH larger, but this is the basic structure.

It is ordered by animal_id. I want to sort it by animal_name.

I have Googled (a lot) and usort is coming out on top but I cannot quite understand it. Can anyone help here?

Cheers

so… the short answer is that the best way to do this is to modify how find returns the data. But something tells me that would have significant effects down the line.

Usort is the best solution for taking what you’ve got, and transforming it into what you want. I am going to let me brain ramble for a bit, and tell me if I lose you somewhere.

Usort takes two parameters: an array to do the sorting on (self-explanitory here, i hope), and a callback function that actually does the comparrison between two items in the array.

The function can be a predefined one, one elsewhere in your script, or what’s called a lambda (also called anonymous) function - a function that exists only for the purposes of being in this slot and doesnt exist afterward. It has no name, and if you want to reuse it, you’ll have to recreate it.

A function that the usort is going to call needs to take two parameters (usually referred to as a and b, but you can name the variables to your liking), and needs to return one of three values:
-1, if a should go before b,
1, if b should go before a,
or 0, if they are equal (equal things do not change their order.)

Usort walks the array from start to finish, applying the function to each pair of values until the array is sorted.
Note: Usort is an in-place function. Usort returns true if it succeeded, or false if it did not. The array is mutated, rather than returned.

In this case, you would send $services into usort, and have the function compare a[0]->animal_name to b[0]->animal_name.

1 Like

Hi, m_huntley.

Thank you very much for your response. You’ve given me enough triggers to get this working nicely. I do find the usort process difficult to get my head around but have used it successfully anyway.

Here’s what I have now:

public function getServices($vertical_id)
    {
        $relevantServices = $this->verticalToServiceTable->find('vertical_id', $vertical_id);
        $services = [];
        foreach ($relevantServices as $verticalService) {
            $service = $this->servicesTable->find('service_id', $verticalService->service_id);
            $services[] = $service;
        }
        usort($services, [$this, 'sortServices']);        
        return $services;
    }

    private function sortServices ($a, $b) {
        $a = $a[0]->page_title;
        $b = $b[0]->page_title;

        if ($a == $b) {
            return 0;
        }
        return $a < $b ? -1 : 1;
    }

Woks beautifully.

Cheers,

If you’re on PHP 7.0+ you can replace this with this:

usort($services, static function ($a, $b) {
    return $a[0]->page_title <=> $b[0]->page_title;
});

If you’re on PHP 7.4+ you can take it one step further:

usort($services, static fn ($a, $b) => $a[0]->page_title <=> $b[0]->page_title);

Your version and these two versions do the exact same thing, using different syntax.

1 Like

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.