user1219742
user1219742

Reputation:

PHP: Sorting arrays with values like -1- and -10-

I have a function that gets filenames from a directory, and then puts them in an array. All the filenames start with a code, as an example: -0-filename.php, -1-filename.php, -2-filename.php and -10-filename.php.

After some steps, the filenames are echoed out. The process looks like this:

rsort( $archiveArray );
$amount = count( $archiveArray );
$i = 0;
while( $i <= $amount )
{
    echo $archiveArray[$i];
    $i++;
}

Anyways. The problem is; when I get 10 files in the directory, and try to do the echoing process above, I get the names in a wrong order. - It's supposed to be :

-10-filename.php

-9-filename.php

-8-filename.php

...

-1-filename.php

-0-filename.php

But instead, I get

-9-filename.php

-8-filename.php

...

-10-filename.php

-1-filename.php

-0-filename.php

What's the quickest and easiest way to fix this?

EDIT:

If it wasn't obvious, the filenames are not always identical, even when not including the codes. The are always in this format: -number-randomtext.php, where number is always one higher than the last one, and randomtext can really be anything.

Upvotes: 1

Views: 2509

Answers (5)

vascowhite
vascowhite

Reputation: 18440

I used usort() to do this:-

$files = array('-10-filename.php', '-9-filename.php', '-8-filename.php', '-10-filename.php', '-1-filename.php', '-0-filename.php');
    $cmp = function($a, $b){
        list($mt, $num1, $name) = explode('-', $a);
        list($mt, $num2, $name) = explode('-', $b);
        return $num1 - $num2;
    };
    usort($files, $cmp);
    var_dump($files);

Gave me this output:-

array
  0 => string '-0-filename.php' (length=15)
  1 => string '-1-filename.php' (length=15)
  2 => string '-8-filename.php' (length=15)
  3 => string '-9-filename.php' (length=15)
  4 => string '-10-filename.php' (length=16)
  5 => string '-10-filename.php' (length=16)

If you want them sorted in reverse just change the last line in the comparison function to:-

return $num2 - $num1;

As an aside, you may find a comparison of PHP sort functions useful.

Upvotes: 0

kitti
kitti

Reputation: 14814

Using rsort with SORT_NATURAL works if you're running PHP 5.4. If you're not, however:

natsort( $archiveArray );
$archiveArray = array_reverse( $archiveArray );

...will do the same thing. Just use natsort to do the natural order sorting, then reverse the array.

Test code (PHP 5.3.3):

php > $array = array( '-1-blah', '-2-foo', '-12-boo', '-11-yaay', '-3-bar' );
php > natsort( $array );
php > print_r( $array );
Array
(
    [0] => -1-blah
    [1] => -2-foo
    [4] => -3-bar
    [3] => -11-yaay
    [2] => -12-boo
)
php > $array = array_reverse( $array );
php > print_r( $array );
Array
(
    [0] => -12-boo
    [1] => -11-yaay
    [2] => -3-bar
    [3] => -2-foo
    [4] => -1-blah
)
php > 

Upvotes: 1

JYelton
JYelton

Reputation: 36512

Another way to do this is usort, and write your own sorting criteria.

I used regular expressions to parse the numeric value from the string, as follows:

$files = array(
    '-0-filename.php',
    '-1-filename.php',
    '-2-filename.php',
    '-3-filename.php',
    '-4-filename.php',
    '-5-filename.php',
    '-6-filename.php',
    '-7-filename.php',
    '-8-filename.php',
    '-9-filename.php',
    '-10-filename.php',
    '-11-filename.php',
    );

usort($files, 'CustomFileSequence');

var_dump($files);

function CustomFileSequence($a, $b)
{
    $pattern = '/^\\-([0-9]*)\\-/';
    preg_match($pattern, $a, $matches);
    $a_val = $matches[1];
    preg_match($pattern, $b, $matches);
    $b_val = $matches[1];

    if ($a_val < $b_val)
        return 1;
    if ($a_val > $b_val)
        return -1;
    if ($a_val == $b_val)
        return 0;
}

Output is:

array
  0 => string '-11-filename.php' (length=16)
  1 => string '-10-filename.php' (length=16)
  2 => string '-9-filename.php' (length=15)
  3 => string '-8-filename.php' (length=15)
  4 => string '-7-filename.php' (length=15)
  5 => string '-6-filename.php' (length=15)
  6 => string '-5-filename.php' (length=15)
  7 => string '-4-filename.php' (length=15)
  8 => string '-3-filename.php' (length=15)
  9 => string '-2-filename.php' (length=15)
  10 => string '-1-filename.php' (length=15)
  11 => string '-0-filename.php' (length=15)

Upvotes: 1

Jon Egeland
Jon Egeland

Reputation: 12613

You need to convert the number to an int value. Right now it's being interpreted as a string. You can just do something like this:

$names =  // your array of file names.
$sorted = // the sorted version names.

for($i = 0; $i < count($arr); $i++) {
  $sorted[substr($names[$i], 1, strpos($names[$i], '-', 2))] = $names[$i];
}

print_r($sorted);

Basically, you take the name from $names, give it an index in the sorted array based on the number between the two -s, and add it to $sorted.

Upvotes: 0

AndrewR
AndrewR

Reputation: 6748

rsort has an optional second parameter called sort_flags. use SORT_NATURAL to do a "natural sort".

rsort($archiveArray, SORT_NATURAL);

Upvotes: 2

Related Questions