Sorting an array of directory filenames in descending natural order
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');
精彩评论