Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
?
Solved

PHP Sort 2-D Array Elements by Date in Sub-key (Both ASC and DESC)

Posted on 2007-10-03
17
Medium Priority
?
339 Views
Last Modified: 2013-12-13
I have a 2-D array with hundreds of elements, with a structure like shown below.  I need to sort the array so that main elements (e.g. 0 through 999, in the example below) appear in order of the date (which appears in key 7 of each element.
    I need to give users the choice of sorting by Ascending or Descending (Least Recent or Most Recent).
    What PHP Code will sort like that quickly, and how could it be used for either ASC or DESC, per user's choice?

Array
(
    [0] => Array
        (
            [0] => 0
            [1] => Field One 0
            [2] => Field Two 0
            [3] => Field Three 0
            [4] => Field Four 0
            [5] => Field Five 0
            [6] => Field Six 0
            [7] => 2007-10-03
        )

    [1] => Array
        (
            [0] => 1
            [1] => Field One 1
            [2] => Field Two 1
            [3] => Field Three 1
            [4] => Field Four 1
            [5] => Field Five 1
            [6] => Field Six 1
            [7] => 2005-11-29
        )

   .   .   .   etc.  .  .  .

    [999] => Array
        (
            [0] => 999
            [1] => Field One 999
            [2] => Field Two 999
            [3] => Field Three 999
            [4] => Field Four 999
            [5] => Field Five 999
            [6] => Field Six 999
            [7] => 2006-12-30
        )
)
0
Comment
Question by:FrankTech
  • 7
  • 6
  • 4
17 Comments
 
LVL 34

Assisted Solution

by:Beverley Portlock
Beverley Portlock earned 1000 total points
ID: 20007653
This is a little messy, but it will do what you want...





<?php
$arr = array
(
    array
        (
            '0' => '0',
            '1' => 'Field One 0',
            '2' => 'Field Two 0',
            '3' => 'Field Three 0',
            '4' => 'Field Four 0',
            '5' => 'Field Five 0',
            '6' => 'Field Six 0',
            '7' => '2007-10-03'
        ),

     array
        (
            '0' => '1',
            '1' => 'Field One 1',
            '2' => 'Field Two 1',
            '3' => 'Field Three 1',
            '4' => 'Field Four 1',
            '5' => 'Field Five 1',
            '6' => 'Field Six 1',
            '7' => '2006-12-30'
        ),

    array
        (
            '0' => '999',
            '1' => 'Field One 999',
            '2' => 'Field Two 999',
            '3' => 'Field Three 999',
            '4' => 'Field Four 999',
            '5' => 'Field Five 999',
            '6' => 'Field Six 999',
            '7' => '2005-11-29'
        )
);

echo "<pre>";print_r( $arr);"</pre>";

function cmp($a, $b)
{
     global $arr;

     $dt1 = $arr[$a]['7'];
     $dt2 = $arr[$b]['7'];

     return strcmp( $dt1, $dt2 );
}




uksort($arr, "cmp");



echo "<pre>";print_r( $arr);"</pre>";


?>
0
 
LVL 34

Assisted Solution

by:Beverley Portlock
Beverley Portlock earned 1000 total points
ID: 20007663
To get DESCENDING just change the comparison round from


     return strcmp( $dt1, $dt2 );

to


     return strcmp( $dt2, $dt1 );
0
 
LVL 13

Expert Comment

by:MasonWolf
ID: 20007929
Here's an easier way. Just have $asc = true for ascending or false for descending:

uksort($array, create_function('$a,$b', 'if($a[7] == $b[7]) return 0; return ($a[7] < $b[7]) ? '. (($asc) ? '-1 : 1;' : '1 : -1;')));
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:FrankTech
ID: 20007951
Thanks. That seems to work.  I made two functions, one for ASC and one for DESC:

function cmpasc($a, $b)
{
     global $arr;
     $dt1 = $arr[$a]['7'];
     $dt2 = $arr[$b]['7'];
     return strcmp( $dt1, $dt2 ); // ASC
}

function cmpdesc($a, $b)
{
     global $arr;
     $dt1 = $arr[$a]['7'];
     $dt2 = $arr[$b]['7'];
       return strcmp( $dt2, $dt1 ); // DESC
}

Now what's the best way to allow the user to specify which of these statements to run:

     uksort($arr, "cmpasc"); // for ASC
                                              or
     uksort($arr, "cmpdesc"); // for DESC

Maybe something like this (?) at the appropriate line in the script (the place where I need the sorting to happen):

     if ($_POST['order'] == 'asc') {
        uksort($arr, "cmpasc");
    } elseif ($_POST['order'] == 'desc') {
        uksort($arr, "cmpdesc");
    } else {
       // not sorted, use raw order
    }

Is there a better or simpler way?  For example, can the sort order be sent into a single function as a parameter? If so, how?
0
 

Author Comment

by:FrankTech
ID: 20008004
I didn't see Mason Wolf's response before I posted my comment to bportlock.  A question for both of you:  which of your approaches is likely to run the fastest?  Eventually I may have thousands of elements, and it will need to run quickly and not use too much memory.  
0
 
LVL 13

Expert Comment

by:MasonWolf
ID: 20008009
Did I not get mine up fast enough? :)

You could use a simple radiobutton with mine to specify the $asc variable:

<input type="radio" name="asc" value="1" />ASC <input type="radio" name="asc" value="0" />DESC

If you don't have register_globals on (which is probably a good idea), then just replace "$asc" in the function I provided with "$_POST['asc']".
0
 
LVL 13

Expert Comment

by:MasonWolf
ID: 20008033
Probably mine. If you have to sort thousands of arrays, then bportlock's without question. But if you're just sorting once, even on a large array, my "fire and forget" approach to the sorting function is probably going to be quicker, though not by much.

BP? What do you think?
0
 
LVL 34

Expert Comment

by:Beverley Portlock
ID: 20008081
If you are running it on a half-decent server, I don't think it will make any difference. I routinely handle large data sets in PHP and I'm always surprised at how quick it is for an interpreted language.
0
 
LVL 34

Expert Comment

by:Beverley Portlock
ID: 20008095
Second thoughts - execution SPACE is more likely to be a problem than execution TIME. Many PHP installations are limited to 8MB of RAM. If you can edit php.ini and up the space limit then do so.
0
 

Author Comment

by:FrankTech
ID: 20008104
MasonWolf,
    I like the idea of creating a function dynamically, but can't get your code to work.  Here's how I'm testing it:

$asc = "TRUE"; // ASC
// $asc = "FALSE"; // DESC

uksort($arr, create_function('$a,$b', 'if($a[7] == $b[7]) return 0; return ($a[7] < $b[7]) ? '. (($asc) ? '-1 : 1;' : '1 : -1;')));

I also tried it with:
    $asc = 1; // ASC
    // $asc = 0; // DESC

The I re-named the array as $arr (instead of $array) in the function, to match my array name; and I ran the statement at the same line as BP's code.  But the sort order is not affected. What am I doing wrong?  
0
 
LVL 13

Expert Comment

by:MasonWolf
ID: 20008138
You're using string versions for true and false. The $asc = 1 should work, but $asc = "TRUE" wouldn't.

Try:
$asc = true; //ASC
//$asc = false; //DESC

I tested my code before I posted, and that worked for me.
0
 

Author Comment

by:FrankTech
ID: 20008254
Mason Wolf,
  It still doesn't work. (Seems like the function is not running at all, as it has no effect.)  I'm not sure what else could be wrong, especially since the code tested as working before you posted it.  Maybe some difference in the PHP version ( I'm on 5.2.4 on WAMP)?
0
 
LVL 13

Accepted Solution

by:
MasonWolf earned 1000 total points
ID: 20008347
My localhost testing server is 5.2.4 and it worked fine. You can see it for yourself online at http://hiremasonwolf.com/ee_test/untitled.php

The online server is version 4.4.4

Here's the exact code for that page:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
</head>

<body>
<?php
$array = array(0 => array(0 => 0,1 => 'Field One 0',2 => 'Field Two 0',3 => 'Field Three 0',4 => 'Field Four 0',5 => 'Field Five 0',6 => 'Field Six 0',7 => '2007-10-03'), 1 => array(0 => 1, 1 => 'Field One 1', 2 => 'Field Two 1', 3 => 'Field Three 1', 4 => 'Field Four 1', 5 => 'Field Five 1', 6 => 'Field Six 1', 7 => '2005-11-29'), 999 => array(0 => 999, 1 => 'Field One 999', 2 => 'Field Two 999', 3 => 'Field Three 999', 4 => 'Field Four 999', 5 => 'Field Five 999', 6 => 'Field Six 999', 7 => '2006-12-30'));
$asc = false;
usort($array, create_function('$a,$b', 'if($a[7] == $b[7]) return 0; return ($a[7] < $b[7]) ? '. (($asc) ? '-1 : 1;' : '1 : -1;')));
echo "<pre>";
var_dump($array);
echo "</pre>";
$asc = true;
usort($array, create_function('$a,$b', 'if($a[7] == $b[7]) return 0; return ($a[7] < $b[7]) ? '. (($asc) ? '-1 : 1;' : '1 : -1;')));
echo "<pre>";
var_dump($array);
echo "</pre>";
echo phpversion();
?>
</body>
</html>
0
 

Author Comment

by:FrankTech
ID: 20008627
MasonWolf:
   It works now.  Maybe the difference is because your earlier post said "uksort", your working version uses "usort".   (I think I like usort better, anyway, as it always makes the first element 0 no matter which way the sort goes.)

bportlock:
    I think both experts' suggestions are useful, for different purposes. I'll increase and split the points.  Any comments on how to pass a sort order variable into your function, instead of having two functions and a conditional branch?  Thanks.
0
 
LVL 13

Expert Comment

by:MasonWolf
ID: 20008651
uksort versus usort shouldn't have made a difference (I tested both). But it works, so I won't belabor the point. I'm glad your happy. Thanks for the point increase and split.
0
 
LVL 13

Expert Comment

by:MasonWolf
ID: 20008728
By the way, you can declare a variable "$var" outside the function, and then give the function the ability to use it by placing "global $var;" inside the function at the top. That'll let you use BP's method with the ascend / descend passed in from your user rather than a conditional branch.
0
 

Author Comment

by:FrankTech
ID: 20008765
Good idea.  Thanks MasonWolf.
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Password hashing is better than message digests or encryption, and you should be using it instead of message digests or encryption.  Find out why and how in this article, which supplements the original article on PHP Client Registration, Login, Logo‚Ķ
This article discusses how to create an extensible mechanism for linked drop downs.
The viewer will learn how to dynamically set the form action using jQuery.
The viewer will learn how to look for a specific file type in a local or remote server directory using PHP.
Suggested Courses

580 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question