【问题标题】:How do I organise a PHP foreach loop by the filename it spits out?如何通过它吐出的文件名组织 PHP foreach 循环?
【发布时间】:2011-08-03 10:30:48
【问题描述】:

所有

我正在尝试组织一个由 foreach 循环返回的文件列表 - 这些文件标有一个月:例如报告 - 2011 年 1 月,报告 - 2011 年 2 月等

他们目前以随机顺序吐出它们,例如 7 月、2 月、12 月、3 月,我希望它们按 1 月、2 月、3 月、4 月等顺序出现。

你们能否说明我将如何做到这一点。

这是我的功能:

function getDirectoryList($directory) {
$results = array();
$handler = opendir($directory);
while ($file = readdir($handler)) {
    if ($file != "." && $file != ".." && $file != "img") {
        $results[] = $file;
    }
}
closedir($handler);
return $results;
}

这是对函数的调用:(注意“文件路径”是使用define()设置的)

$files = getDirectoryList(filepath.$username."/".date("Y"));

这是 foreach 循环:

foreach ($files as $f) {    
$path_parts = pathinfo(filepath.$f);
$dir = $path_parts['dirname'];
$base = $path_parts['basename'];
$ext = $path_parts['extension'];
$fname = $path_parts['filename'];

echo "<div class='file ".$ext."'>".
    "<a href='".downloadpath.$username."/".$f."' target='_blank' title='Download $f'>". $fname ."</a>
    <span class='del'><a href='../inc/delete.php?id=".$_GET["id"]."&amp;f=$f' title='Delete $f'>Delete</a></span>
    </div>";
}

【问题讨论】:

  • 为什么不对数组使用排序?
  • 问题本质上是“如何按日期排序这个数组”...sort() 不会那样做。

标签: php foreach


【解决方案1】:

在循环之前对数组进行排序

function cmp($a, $b) {
  $a = pathinfo(filepath.$a);
  $b = pathinfo(filepath.$b);
  $months = array(1 => 'January', 2 => 'February', 3 => 'March', 4 => 'April', 5 => 'May', 6 => 'June', 7 => 'July', 8 => 'August', 9 => 'September', 10 => 'October', 11 => 'November', 12 => 'December');

  $a_val = $b_val = 0;
  foreach ($months as $value => $month) {
    if (stripos($a['filename'], $month) !== false) $a_val = $value;
    if (stripos($b['filename'], $month) !== false) $b_val = $value;
  }
  return ($a_val < $b_val) ? -1 : 1;
}

uasort($files, 'cmp');

【讨论】:

  • 但这会按字母顺序对它们进行排序,而目标是按时间顺序对它们进行排序。
  • +1 和我写的一样 =) 你得到了徽章#fast_writer =)
  • 您也可以将它们分组到一个月份数组中,同时通过 foreach 循环,具有:array('january' =&gt; array('report1.csv', 'report2.csv'), 'february' =&gt; array('report3.csv') 该数组应该按月份顺序预先排序
  • 您为每次调用 cmp 创建并迭代了月份数组。有优化空间。
  • @Jens 我们可以用 C 语言编写比较函数并将其编译为 PHP 扩展。总是有优化的空间。你今天的cmets很奇怪。
【解决方案2】:

使用usort 对数组进行排序。

usort($files, 'cmp');

使用关联数组设置比较标准:

$months = array ("january" => 0, "february" => 1, ...);

设置比较功能:

function cmp($file1, $file2) {
    $months = array ("january" => 0, "february" => 1, ...);
    // or global $months;
    // or $this->months;
    $month1 = ... extract month from $file1;
    $month2 = ... extract month from $file2;
    return $months[$month1] < $months[$month2] ? -1 : 1;
}

从文件中提取月份字符串:

preg_match("/^\w+/", $file, $match);
$month = $match[0];

编辑:

数组 $months 不需要存储在 cmp 方法中。这将导致每次调用该方法时都创建数组。改用 OOP 方法或全局关键字 global $months

【讨论】:

  • 如果函数中没有包含 $months 数组,则会污染全局变量空间,如果代码中的其他地方有 $months 变量,这会搞砸。
  • 您可以设置一个静态类以及托管月份数组。或者任何你想要的。范围不是这个问题的主题。
【解决方案3】:

试试ksortfilemtime

function getDirectoryList($directory) {
$results = array();
    $handler = opendir($directory);
    while ($file = readdir($handler)) {
        if ($file != "." && $file != ".." && $file != "img") {
            $inDate = filemtime($directory.$file);
            $results[$inDate] = $file;
        }
    }
    closedir($handler);
    ksort($results);
    return $results;
}

【讨论】:

  • 这就是为什么我添加了$results[$inDate] = $file; 以做出正确的订购
  • 我的意思是我们不知道一月是否在二月之前被修改过。
【解决方案4】:

使用自定义函数对您的 $files 数组使用 usort。

function my_sort($a,$b) {
     $month = array (
        'january' => 1,
        'february' => 2,
        'march' => 3,
        'april' => 4,
        'may' => 5,
        'june' => 6,
        'july' => 7,
        'august' => 8,
        'september' => 9,
        'october' => 10,
        'november' => 11,
        'december' => 12
    );

    // Might need to extract month from filename here
    $a_idx = $month[$a['filename']];
    $b_idx = $month[$b['filename']];

    if ($a_idx == $b_idx) {
        return 0;
    }
    else {
        return ($a_idx < $b_idx ? -1 : 1);
    }
}

usort($files,'my_sort');

【讨论】:

    【解决方案5】:
    function getSortableDate( $s ) {
        $months = array( 'january' => '01', 'february' => '02', 'march' => '03', ... );
        preg_match( '/^(\w+) (\d+)$/', $s, $matches );
        return $matches[2].$months[ $matches[1] ];
    }
    
    function cmp($a, $b) {
        return ( getSortableDate( $a['filename'] ) < getSortableDate( $b['filename'] ) ) ? -1 : 1;
    }
    
    uasort( $files, 'cmp' );
    

    或者,您可以在排序之前将 getSortableDate() 应用于所有文件名,然后使用简单的字符串比较进行排序,这将通过防止多余的 getSortableDate() 调用来加快处理速度。

    但我个人不会这样做,这太过分了,只需将您的文件重命名为 2011-01 2011-02 等。这样它们就可以作为字符串进行比较。

    【讨论】:

    • getSortableDate 为每个 cmp 调用调用 2 次,这导致创建了许多相同的 $match 数组。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-13
    • 1970-01-01
    • 2017-01-27
    相关资源
    最近更新 更多