Question about usort() and using comparison operators in compare function

Here is the situation: I want to order array of items based on items LEVEL value (item = also array, and one of the item keys is LEVEL which holds integer number). LEVEL is number but it is type of string since the data comes from database, dunno if it would matter if the type of LEVEL was int(?) So this is what I have now and it seems to do the job.

This is what I had before running it through the sortItemsByLevel() function:

array (size=6)
  0 => 
    array (size=2)
      'ID' => string '2999' (length=4)
      'LEVEL' => string '0' (length=1)
  1 => 
    array (size=2)
      'ID' => string '3000' (length=4)
      'LEVEL' => string '2' (length=1)
  2 => 
    array (size=2)
      'ID' => string '3001' (length=4)
      'LEVEL' => string '2' (length=1)
  3 => 
    array (size=2)
      'ID' => string '3004' (length=4)
      'LEVEL' => string '2' (length=1)
  4 => 
    array (size=2)
      'ID' => string '3002' (length=4)
      'LEVEL' => string '3' (length=1)
  5 => 
    array (size=2)
      'ID' => string '3003' (length=4)
      'LEVEL' => string '4' (length=1)

And this is what I get as result (which is correct):

array (size=6)
  0 => 
    array (size=2)
      'ID' => string '3003' (length=4)
      'LEVEL' => string '4' (length=1)
  1 => 
    array (size=2)
      'ID' => string '3002' (length=4)
      'LEVEL' => string '3' (length=1)
  2 => 
    array (size=2)
      'ID' => string '3004' (length=4)
      'LEVEL' => string '2' (length=1)
  3 => 
    array (size=2)
      'ID' => string '3001' (length=4)
      'LEVEL' => string '2' (length=1)
  4 => 
    array (size=2)
      'ID' => string '3000' (length=4)
      'LEVEL' => string '2' (length=1)
  5 => 
    array (size=2)
      'ID' => string '2999' (length=4)
      'LEVEL' => string '0' (length=1)

Here is the code:

function sortItemsByLevel($itemsArray) {
    usort($itemsArray, 'compareLevel');
    return $itemsArray;
}

function compareLevel($a, $b)
{
    return $a['LEVEL'] < $b['LEVEL'];
}

Now the question is can I use comparison operators in the compare function like that? Can I trust this result?
I didn’t really find much information on internet about using comparison operators in comparison function anywhere, just happened to test it and it worked. Can someone explain me how this line exactly does the magic:

return $a['LEVEL'] < $b['LEVEL'];

and is this working code or some arbitrary stuff that just happened to work this time.
Most stuff I found from net just told to return -1, 1 or 0 from compareLevel function.
I want to be sure because this sorted data is used to delete stuff from DB in that order and there is no room for mistakes.
Thanks!

PHP is intelligent enough to cross-cast an integer string to an int before doing a comparison on it.

That said… does the ID not matter, if it’s being used in a database delete? Are you erasing entire levels from the database at a time?

1 Like

if you really want to be sure you could always do something like:

return (int) $a['LEVEL'] < (int) $b['LEVEL'];
1 Like

yes. no.

from http://php.net/usort:

The comparison function must return an integer less than, equal to, or greater than zero if the first argument is considered to be respectively less than, equal to, or greater than the second.

1 Like

Check out my answer in this thread. You can get a better id on how to formulate your comparison function from it.

Scott

1 Like

Thanks for the replies.

So I read the message by s_molinari and combined it with Pepster’s answer so I ended up using this:

function compareLevel($a, $b)
{
    $retval = ((int)$a['LEVEL'] < (int)$b['LEVEL'] ? 1 : -1);
    return $retval;
}

As far as I am concerned this should be safe and sound now.

A little background for this whole situation. The whole thing is a bubblegum solution. LEVEL is the depth in a tree structure. When user deletes an item then all the children of that item should be deleted too. So now I have to re-order it so the most grandchild item will be deleted first to prevent getting error from foreign key constraint.

A real solution to this problem would be alter the table to use ON DELETE CASCADE on the constraint which would do the job automatically. But the reason why I won’t and can’t do that is because the system is huge and it was made by another company so nobody inside this company really knows the application code at all (which is Java+OracleDB with one million frameworks). And thus if I altered the table, who knows what other stuff it would affect in the application and I must be 100% sure it won’t affect anything else.

Cheers,
TeNDoLLA

what if the levels are equal? then it should return 0 but instead it returns -1.

Yeah I was thinking that too but in THIS case the equal LEVELs order in the array does not matter. As long as they all are in the correct spot in the array compared to larger and smaller LEVELs. But yeah its good to point out because in some other scenario it could matter.

Cheers,
TeNDoLLA

I assume that your dataset is only the members of the target item’s tree, then… but then you wouldnt need to sort, you’d just erase the entire set. So i’m confused.

Your methodology doesnt seem to match your description.

What do you mean by “just erase the entire set”?

What I have is a huge tree of items. If user deletes anywhere in the tree an item, be it root, child or grandchild. If this deleted item has children or grandchildren or even more deep structure. Those need to be also deleted. When user deletes item I get the ID of that item. Then I query to find all the ID’s and LEVEL of items under that deleted item. The LEVELs I get is in order from smallest to biggest (means the root is first). I cannot delete them in that order because I get error from foreign key constraint. I need to reverse the list to have largest LEVEL first.

Ahhh see, the foreign key constraint is what does it. But… if there is a foreign key constraint… you should be able to cascade properly…

Check my earlier post: Question about usort() and using comparison operators in compare function - #6 by TeNDoLLA to see why I am not cascading properly.

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