'PHP sort array of objects by two properties

I have an array

Array
(
[0] => stdClass Object
    (
        [tab_option_name_selector] => 2
        [fieldtype] => notes
        [order] => 12
    )

[1] => stdClass Object
    (
        [tab_option_name_selector] => 2
        [fieldtype] => notes
        [order] => 8
    )

[2] => stdClass Object
    (
        [tab_option_name_selector] => 1
        [order] => 2
        [fieldtype] => selectbox
    )

[3] => stdClass Object
    (
        [tab_option_name_selector] => 2
        [order] => 3
        [fieldtype] => selectbox
    )
)

I'm trying to get this usort function to work

function osort(&$array, $props) 
{ 
    if(!is_array($props)) 
        $props = array($props => true); 

    $me = usort($array, function($a, $b) use ($props) { 
        foreach($props as $prop => $ascending) 
        { 
            if($a->$prop != $b->$prop) 
            { 
                if($ascending) 
                    return $a->$prop > $b->$prop ? 1 : -1; 
                else 
                    return $b->$prop > $a->$prop ? 1 : -1; 
            } 
        } 
        return -1; //if all props equal        
    });    
    print_r($props);
    return ($me);
} 


$tab = osort($objectArray, "tab_option_name_selector", "order"); 

so sorting by the tab then order.

$tab is empty - any ideas what I'm doing wrong?



Solution 1:[1]

Why the extra level of indirection and making things more confusing? Why not usort directly with usort($objectArray, "sortObjects"); using a sortObjects($a,$b) function that does what any comparator does: return negative/0/positive numbers based on the input?

If the tabs differ, return their comparison, if they're the same, return the order comparison; done.

$array = array(
    (object)array(
        'tab_option_name_selector' => 2,
        'fieldtype' => 'notes',
        'order' => 12
    ),
    (object)array(
        'tab_option_name_selector' => 2,
        'fieldtype' => 'notes',
        'order' => 8
    ),
    (object)array(
        'tab_option_name_selector' => 1,
        'order' => 2,
        'fieldtype' => 'selectbox'
    ),
    (object)array(
        'tab_option_name_selector' => 2,
        'order' => 3,
        'fieldtype' => 'selectbox'
    )
);

function compareTabAndOrder($a, $b) {
    // compare the tab option value
    $diff = $a->tab_option_name_selector - $b->tab_option_name_selector;
    // and return it. Unless it's zero, then compare order, instead.
    return ($diff !== 0) ? $diff : $a->order - $b->order;
}

usort($array, "compareTabAndOrder");
print_r($array);

Solution 2:[2]

Why don't you use array_multisort? http://php.net/manual/de/function.array-multisort.php

$data = //your array

//Create independent arrays
foreach ($data as $row) {
  foreach ($row as $key => $value){
    ${$key}[]  = $value; 
    //Creates $tab_option_name_selector, $fieldtype and $order array
    //in order to use them as independent arrays in array_multisort.
  }  
}

array_multisort($tab_option_name_selector, SORT_ASC, $order, SORT_ASC, $data);

//$data sorted as expected.
echo "<pre>";
print_r($data);
echo "</pre>";

Solution 3:[3]

An example for unlimited number of properties:

$data = [
    (object)['volume' => '1', 'edition'  => '1'],
    (object)['volume' => '2', 'edition'  => '1'],
    (object)['volume' => '3', 'edition'  => '10'],
    (object)['volume' => '3', 'edition'  => '50'],
    (object)['volume' => '3', 'edition'  => '20'],
    (object)['volume' => '4', 'edition'  => '3'],
];

// sorting list by properties
$sorting = ['volume' => SORT_DESC, 'edition' => SORT_ASC];

$arrays = [];
foreach ($sorting as $key => $sort) {
    $column = array_column($data, $key);
    if (!empty($column)) {
        $arrays[] = $column;
        $arrays[] = $sort;
    }
}

if (!empty($arrays)) {
    $arrays[] = $data;
    if (!array_multisort(...$arrays)) {
        var_dump('some error');
        die();
    }
    // get last array, that is the sorted data
    $data = ($arrays[array_key_last($arrays)]);
}

Example partially from php.net - array_multisort

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 Aldo