Sorting an array of directory filenames in descending natural order

十年热恋 提交于 2020-07-03 12:23:51

问题


I have a content directory to be returned in descending natural order.

I'm using scandir() and natsort(), but the addition of array_reverse() yields no results.

I've been researching using a combination of opendir() and readdir() as well what ever else to affect this outcome.

The items to be sorted are numbered image files. They are to be returned as: 10 9 8 7 and so on, but like from like 1000 999 998 997 ... until 0

Here's my current code:

$dir = 'dead_dir/dead_content/';
$launcher = scandir($dir);
natsort($launcher);
array_reverse($launcher, false);
foreach ($launcher as $value) {
    if (in_array(pathinfo($value, PATHINFO_EXTENSION), array('png'))) {
        echo '<img src="dead_dir/dead_content/'.$value.'" />'
    }
}

回答1:


 $dir='dead_dir/dead_content/';
 $launcher= scandir($dir);
 natsort($launcher);
 $r_launcher = array_reverse($launcher,true);

 foreach($r_launcher as $value ){
   if(in_array(pathinfo($value, PATHINFO_EXTENSION),array('png'))){
       echo '<img src="dead_dir/dead_content/'.$value.'" />'}}



回答2:


The problem is simple. array_reverse() does not modify by reference. You are confusing the behavior of sort()ing functions. Instead, you merely need to use the returned value that it generates. That said, there is a better way. Read on...

Since PHP5.4, rsort($array, SORT_NATURAL) will sort your array in DESC order and treat consecutive numbers as numbers instead of strings. This is a more direct and concise way technique versus natsort()ing then array_reverse()ing.

(Demo)
(Demo with .jpg extensions)
(Demo with static string before numbers)

I recommend using glob() to scan your directory. This way you can add the .png filter in the same call.

$dir = 'dead_dir/dead_content/';
$filepaths = glob($dir . '*.png');
rsort($filepaths, SORT_NATURAL);
foreach ($filepaths as $filepath) {
    echo '<img src="' . $filepath . '" />';
}

If you would rather omit the path and just return the filenames, just change your current working directory.

chdir('dead_dir/dead_content');
$filenames = glob('*.png');
rsort($filenames, SORT_NATURAL);
foreach ($filenames as $filename) {
    echo "<div>.png filename => $filename</div>";
}

Now, if you require more specialized handling of the filenames, then a custom sorting function may serve you well.

As demonstrated in the following snippet, the spaceship operator will auto-magically type juggle digital strings as integers and give the same result as the rsort() solution above. Using the spaceship operator is still more direct than using natsort() then array_reverse().

Code: (Demo)

$filenames = ["10", "1", "100", "1000", "20", "200", "2"];
usort($filenames, function($a, $b) {
    return $b <=> $a;
});

var_export($filenames);

Output:

array (
  0 => '1000',
  1 => '200',
  2 => '100',
  3 => '20',
  4 => '10',
  5 => '2',
  6 => '1',
)

If your filenames have leading or trailing non-numeric characters, you can perform the necessary manipulations to strip the unwanted characters while comparing inside of usort().

If anyone is not familiar with how custom sorting works with the spaceship operator...

  • To achieve ASC order, write $a <=> $b.
  • To achieve DESC order, write $b <=> $a.



回答3:


If your image names will be in the format 123-image_name.jpg, 2323-image_name.jpg, ... this will do:

/**
 * Compares digits in image names in the format "123-image_name.jpg"
 *
 * @param string $img1 First image name
 * @param string $img2 Second image name
 * @return integer -1 If first image name digit is greater than second one.
 * 0 If image name digits are equal.
 * 1 If first image name digit is smaller than second one.
 */
function compareImageNames($img1, $img2){
    $ptr = '/^(\d+)-/'; // pattern

    // let's get the number out of the image names
    if (preg_match($ptr, $img1, $m1) && preg_match($ptr, $img2, $m2)) {
        $first  = (int) $m1[0]; // first match integer
        $second = (int) $m2[0]; // second match integer

        // equal don't change places
        if($first === $second) return 0;

        // if move first down if it is lower than second
        return ($first < $second) ? 1 : -1;
    } else{
        // image names didn't have a digit in them
        // move them to front
        return 1;
    }
}

// sort array
usort($images, 'compareImageNames');


来源:https://stackoverflow.com/questions/7377015/sorting-an-array-of-directory-filenames-in-descending-natural-order

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!