【问题标题】:Help sorting keys帮助排序键
【发布时间】:2010-08-25 08:19:31
【问题描述】:

我需要帮助在 php 中从这个数组中排序 [Time] 数据。对于给定的一天,时间不按顺序排列。 有没有办法对此进行排序?谢谢。

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 ) 

到目前为止,这是我的 php 代码:

<?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);
?>

更新:使用比尔建议的修复后的最新排序。 [Time] 是有序的,但也需要在[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 )

【问题讨论】:

  • 您是否从数据库中获取该数据?
  • 不,我有一个 perl 脚本生成该数据。也想不通。

标签: php sorting


【解决方案1】:

编辑:现在我更好地理解了您的输入数据,我已经测试了这个脚本。

首先我和你一样读取数据文件,但是我直接将数据逐个字段收集到一个二维数组中:

<?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;
  }
}

接下来,我使用传递给usort() 的用户定义排序函数对数据数组进行排序。感谢评论者提出改进此功能的建议。

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

usort($data, "comparebydatetime");

现在数据按日期时间排序,所以我可以简单地输出它:

$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>";

我还添加了一些其他更改以获得更好的 PHP 样式:

  • 缩进保持一致。
  • 即使是一个语句的块也要使用花括号。
  • 使用htmlspecialchars() 输出动态数据(包括字段名、CSS 类等)。

【讨论】:

  • 按词汇比较日期可能会做一些不希望的事情。而对于词法比较,strcmp 是更好的选择。
  • @phadej:谢谢,我已经编辑了上面的内容以将日期转换为 UNIX 时间戳。比较时间戳应该更可靠。
  • @Bill Karwin - 您在比较函数的第一个 if 中分配而不是比较
  • 可能是我错了又累了,不正是OP想要排序的时间吗?
  • sortbydate 的第一个 if 子句中应该有 == 而不是 =。比较函数的更好名称是comparebydate
【解决方案2】:

如果您已经使用 PHP5.3,则可以为此使用堆 (manual|wiki):

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);

然后你可以foreach over $sorter,或者,如果你想堆回一个数组,使用

$sortedData = iterator_to_array($sorter);

如果您还没有使用 PHP5.3,您可以使用比较函数中的代码来usort() 数据。但是顺序将被颠倒(意思是升序)。遍历已排序的数组很容易。

您也可以使用SortingIterator 直接检查数组。

【讨论】:

    【解决方案3】:

    简单地说:遍历您的数组并将每个日期作为每个孩子的键,然后 ksort() 您的结果数组。 如有必要,不要忘记在将日期设置为数组键之前将其转换为 DateTime 中的日期,以便 ksort() 可以处理它:

    $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);
    

    您会丢失原始密钥 (0,1,...,4),但我认为这不是问题?

    【讨论】:

    • 对象不能用作数组键。只有字符串和整数。