开发者

Sorting an array of directory filenames in descending natural order

开发者 https://www.devze.com 2023-04-04 14:40 出处:网络
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 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 we开发者_JAVA技巧ll 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.'" />'
    }
}


 $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.'" />'}}


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.


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

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号