views:

91

answers:

3
+2  Q: 

Help sorting keys

I need help sorting [Time] data from in this array in php. For a given day, the time is NOT in order. Is there a way to sort this? Thanks.

Array ( [0] => Array ( )
[1] => Array (         
               [Server] => server1.name 
               [Date] => Sun Aug 22 2010         
               [Set] => db2.bak_lvm         
               [Time] => 06:00:02         
               [Duration] => 01:28:12         
               [Size] => 72.05 GB         
               [Status] => Succeeded ) 
[2] => Array ( [Server] => server1.name                
               [Date] => Sun Aug 22 2010 
               [Set] => db2.bak_lvm 
               [Time] => 00:00:03 
               [Duration] => 01:49:37 
               [Size] => 187.24 GB 
               [Status] => Succeeded ) 
[3] => Array ( [Server] => server1.name 
               [Date] => Sun Aug 22 2010 
               [Set] => db3.bak_lvm 
               [Time] => 23:00:03 
               [Status] => Unsuccessful ) 
[4] => Array ( [Server] => server1.name 
               [Date] => Sun Aug 22 2010 
               [Set] => db4.bak_lvm  
               [Time] => 04:00:03 
               [Duration] => 00:42:36 
               [Size] => 46.46 GB 
               [Status] => Succeeded ) 

Here's my php code, thus far:

<?php
$data = array();
$InputFile = file("test.txt");
foreach ($InputFile as $line){
    preg_match_all("/([0-9])-([^=]+)=([^;]+);/", $line, $matches, PREG_SET_ORDER);

    $LineData = array();
    foreach ($matches as $information)
       $LineData[$information[2]] = $information[3];
       $data[] = $LineData;
}
    $keys = array('Server', 'Date','Set','Time','Duration','Size','Status');
        echo '<table id="stats"><tr>';
        foreach ($keys as $column)
           echo '<th>' . $column . '</th>';
            echo '</tr>';

        $counter=0;
        foreach ($data as $row){
           $counter ++;
           $class = $counter % 2 === 0 ? 'alt1' : 'alt2';
           echo '<tr class="' . $class . '">';

             foreach ($keys as $column)
                if (isset($row[$column])){
                  echo '<td>' . $row[$column];
                  } else {
                  echo '<td>' . '' . '</td>';
                }
        }
        echo '</table>';
        print_r($data);
?>

Updated: Latest sort after using suggested fix by Bill. [Time] is in order, but also need to have it sorted within [Date]

Array ( [0] => Array (
            [Server] => server1.name
            [Date] => Mon Aug 23 2010
            [Set] => db2.bak_lvm
            [Time] => 00:00:03
            [Duration] => 01:50:24
            [Size] => 187.24 GB
            [Status] => Succeeded )
    [1] => Array ( [Server] => server1.name
                   [Date] => Mon Aug 23 2010
                   [Set] => db3.bak_lvm
                   [Time] => 04:00:02
                   [Duration] => 00:42:28
                   [Size] => 46.47 GB
                   [Status] => Succeeded )
    [2] => Array ( [Server] => server1.name
                   [Date] => Sun Aug 22 2010
                   [Set] => db3.bak_lvm
                   [Time] => 04:00:03
                   [Duration] => 00:42:36
                   [Size] => 46.46 GB
                   [Status] => Succeeded )
    [3] => Array ( [Server] => server1.name
                   [Date] => Mon Aug 23 2010
                   [Set] => db1.bak_lvm
                   [Time] => 06:00:02
                   [Duration] => 01:28:24
                   [Size] => 72.05 GB
                   [Status] => Succeeded )
    [4] => Array ( [Server] => server1.name
                   [Date] => Sun Aug 22 2010
                   [Set] => db4.bak_lvm
                   [Time] => 20:00:03
                   [Duration] => 04:17:57
                   [Size] => 426.60 GB
                   [Status] => Succeeded )
+2  A: 

edit: Now that I understand your input data better, I've tested this script.

First I read the data file as you do, but I collect the data field by field directly into a two-dimensional array:

<?php

$data = array();
$InputFile = file("test.txt");
foreach ($InputFile as $line)
{
  preg_match_all("/([0-9])-([^=]+)=([^;]+);/", $line, $matches, PREG_SET_ORDER);

  foreach ($matches as $information)
  {
    $id = $information[1];
    $field = $information[2];
    $value = $information[3];
    $data[$id][$field] = $value;
  }
}

Next I sort the data array with a user-defined sorting function passed to usort(). Thanks to commenters for suggestions to make this function better.

function comparebydatetime($a, $b) {
  $adate = strtotime($a["Date"]." ".$a["Time"]);
  $bdate = strtotime($b["Date"]." ".$b["Time"]);
  return $adate-$bdate;
}

usort($data, "comparebydatetime");

Now the data is sorted by date and time, so I can simply output it:

$keys = array("Server", "Date","Set","Time","Duration","Size","Status");
echo "<table id='stats'>\n";
echo "<tr>\n";
foreach ($keys as $column)
{
  echo "<th>" . htmlspecialchars($column) . "</th>\n";
}
echo "</tr>\n";

$counter=0;
foreach ($data as $row)
{
  $counter ++;
  $class = $counter % 2 === 0 ? "alt1" : "alt2";
  echo "<tr class='" . htmlspecialchars($class) . "'>\n";

  foreach ($keys as $column)
  {
    echo "<td>";
    if (isset($row[$column]))
    {
      echo htmlspecialchars($row[$column]);
    }
    echo "</td>\n";
  }
  echo "</tr>\n";
}
echo "</table>";

I've also added some other changes for better PHP style:

  • Be consistent about indentation.
  • Use curly-braces even for a block with one statement.
  • Use htmlspecialchars() for outputting dynamic data (including field names, CSS classes, etc.).
Bill Karwin
Comparing Date lexically will probably do something undesired. And for lexical comparison `strcmp` is a better choice.
phadej
@phadej: Thanks, I have edited the above to convert dates to UNIX timestamps. Comparing timestamps should be even more reliable.
Bill Karwin
@Bill Karwin - you're assigning instead of comparing in your comparison function's first `if`
timdev
Maybe I'm wrong and tired, but isn't it the *time* that OP wanted to be sorted ?
bPizzi
There should be `==` not `=` in the first if clause of `sortbydate`. Also better name for the comparison function would be `comparebydate`.
phadej
@Bill K. - Thank you. I am trying your fix although, I'm not having luck executing it. I edited my code block to include the statements for building the array if you can pls check what i'm missing. thank again.
cjd143SD
Sorting by time is probably left as an exercise? :)
phadej
@Bill, why go through the trouble (not that it is much) to return 0, -1 or 1? `return $adate - $bdate;` would get the job done.
salathe
Thanks for the comments everyone. I've made some edits to correct the `==` comparison and date/time references.
Bill Karwin
@salathe: Thanks that would work too. I just get into the habit when writing custom sort functions of doing it the way I showed above because there's not always a convenient arithmetic comparison as you mention.
Bill Karwin
@cjd143SD: I have added more to my answer above. Let me know if that helps.
Bill Karwin
@Bill K. - no luck yet executing it :-( Sorry new to php. I'm trying to figure out why the page won't display. Is there a debug mode?
cjd143SD
@cjd143SD: If it's a blank screen, it probably means you have a syntax error somewhere and the PHP interpreter couldn't parse the script, let alone run it. Enable `error_reporting` and check your HTTP server's error log to monitor such errors.
Bill Karwin
@Bill K - I was able to execute the script. Can you help me get the date sorted? Time is working fine. I added the output from print_r above. Thanks for all your help.
cjd143SD
@cjd143SD: Okay, I've rewritten the code above. I tested it to be sure it works, so try it now.
Bill Karwin
A: 

Simply put : walk over your array and put each date as the key of each child, then ksort() your resulting array. Don't forget to, if necessary, translate your date in DateTime before setting it as an array key, so that ksort() can work throught it:

$to_be_sorted = array();
foreach($array as $child) {
     $date = new DateTime($child["date"].' '.$child["time"]);
     $to_be_sorted[$date] = $child;
}
$sorted = ksort($to_be_sorted);

You'll loose your original keys (0,1,...,4) but I assume that it's not a problem ?

bPizzi
Objects cannot be used as array keys. Only strings and integers.
Gordon
Your right dude. Might get some sleep.
bPizzi
+2  A: 

If you are on PHP5.3 already, you could use a Heap (manual|wiki) for this:

class SortByDateTimeDescending extends SplMaxHeap
{
    public function compare($a, $b)
    {
        if(!empty($a['Date']) && !empty($a['Time']) &&
           !empty($b['Date']) && !empty($b['Time']))
        {
            $timestampA = strtotime("{$a['Date']} {$a['Time']}");
            $timestampB = strtotime("{$b['Date']} {$b['Time']}");
            return $timestampA - $timestampB;
        }
        return 0;
    }
}

$sorter = new SortByDateTimeDescending;
array_map(array($sorter, 'insert'), $data);

You can then foreach over $sorter or, if you want the heap back to an array, use

$sortedData = iterator_to_array($sorter);

If you are not on PHP5.3 yet, you can use the code in the compare function to usort() the data. The order will be reversed though (meaning Ascending). Iterating over the sorted array is easy.

You could also use a SortingIterator to go over the array directly.

Gordon