Archive

Posts Tagged ‘sort’

Sequentially Rename All Image Files In A Directory With PHP

March 2nd, 2009 1 comment

The following function will rename all of the image files in a directory to be sequential. The parameters are the path of the directory that the files are in and the name of a function that will be used to sort the array of files through the PHP usort() funciton.

function sequentialImages($path, $sort=false) {
 $i = 1;
 $files = glob($path."/{*.gif,*.jpg,*.jpeg,*.png}",GLOB_BRACE|GLOB_NOSORT);
 
 if ( $sort !== false ) {
  usort($files, $sort);
 }
 
 $count = count($files);
 foreach ( $files as $file ) {
  $newname = str_pad($i, strlen($count)+1, '0', STR_PAD_LEFT);
  $ext = substr(strrchr($file, '.'), 1);
  $newname = $path.'/'.$newname.'.'.$ext;
  if ( $file != $newname ) {
   rename($file, $newname);
  }
  $i++;
 }
}

The following function can be used in the second parameter to sort the files by their last modified time.

function sort_by_mtime($file1, $file2) {
 $time1 = filemtime($file1);
 $time2 = filemtime($file2);
 if ( $time1 == $time2 ) {
  return 0;
 }
 return ($time1 < $time2) ? 1 : -1;
}

Putting these two function together we can call the sequentialImages() function like this.

sequentialImages('files','sort_by_mtime');

This function takes the following set of images:

file1.gif
file2.gif
wibble.gif
wobble.gif
02.gif

And renames them to the following:

01.gif
02.gif
03.gif
04.gif
05.gif

Categories: PHP Tags: , , , , , , , , , ,

Force Sorting Of VARCHAR Data In MySQL

September 18th, 2008 No comments

If you find that you are having trouble sorting data in a VARCHAR column in a MySQL database then you can try the following trick.

Lets say that you had the values 1,200,30,4000 and 5 and that you inserted them into the database in that order. When the following query is run on this data:

SELECT numbers FROM table ORDER BY numbers;

The following output is seen.

1
200
30
4000
5

This is clearly not the correct order, although it represents the order of. You can force a natural order to the sort by using a "+0" after the colum you are trying to sort by.

SELECT numbers FROM table ORDER BY numbers+0;

This produces the following output, which is sorted as you expect a set of numbers to be sorted.

1
5
30
200
4000

This is essentially the same as casting the number column, as in the following query.

SELECT number FROM test.tests ORDER BY CAST(number AS UNSIGNED);

However, what happens if you added some textual data? Lets take the original dataset and add two text items to it. These are "1,000" and "text". Using the default sort these two text items are unaffected and appear in the order in which they were added. When using the "+0" method anything that is slightly numeric will be placed into the list and anything else will get put at the start of the data.

text
1
1,000
5
30
200
4000

When using the cast method the order is exactly the same, but in this case MySQL throws some exceptions when trying to cast a non numeric value.

If you are storing numbers in your database table and have to use this query to get the correct order then you might want to consider altering the table so that these values are stored as integers.

Categories: MySQL Tags: , , , , ,

Randomise JavaScript Array

July 4th, 2008 No comments

Randomising a JavaScript array can be done in one or two ways. The easy way is to create a function that returns a random number and then use the sort() function of the Array object to sort the array by a random value.

// random number
function randNumber(){
 return (Math.round(Math.random())-0.5);
}
 
// create array
var numbers = new Array(1,2,3,4,5,6,7,8,9);
// print array
alert(numbers);
//randomise array
numbers.sort(randNumber);
//print random array
alert(numbers);

The sort function works by taking the randNumber function as a parameter. For every item of the array it uses this function to compare one value to the next. If the function returns a random number then the array will be sorted randomly.

The second method is slightly more complex and involves using the Fisher Yates randomising algorithm. The following function takes in an array and returns a randomly sorted array.

function fisherYates(myArray){
 var i = myArray.length;
 if(i == 0){
  return false;
 }
 while(--i){
  var j = Math.floor(Math.random() * (i + 1));
  var tempi = myArray[i];
  var tempj = myArray[j];
  myArray[i] = tempj;
  myArray[j] = tempi;
 }
 return myArray;
}

Use the function in the following manner.

var numbers = new Array(1,2,3,4,5,6,7,8,9);
alert(numbers);
numbers= fisherYates(numbers);
alert(numbers);

Categories: JavaScript Tags: , , , ,

Array Sorting Functions In PHP

April 1st, 2008 No comments

There are many ways to sort an array in PHP, the easiest being to use the sort() function built into PHP. This sort function is quick but has it’s limitations, especially when sorting things like dates as PHP usually guesses which value is higher than the other and can produce odd results. However, there are plenty of sorting algorithms available than can allow you to sort an array in any way you want.

The simplest of these is called the bubble sort. Here is a function that will sort an array of values using the bubble sort algorithm.

function bubbleSort($array){
 if(!$length = count($array)){
  return $array;
 };
 for($outer = 0; $outer < $length; $outer++) {
  for($inner = 0; $inner < $length; $inner++) {
   if($array[$outer] < $array[$outer]) {
    $tmp = $array[$outer];
    $array[$outer] = $array[$inner];
    $array[$inner] = $tmp;
   };
  };
 };
}

This algorithm works by running through the array and swapping a value for the next value along if that value is less than the current value. After the first run through the highest value in the array will be at the correct end. It therefore must run through the array once for every item in the array, so it has a low efficiency.

An improvement on this is the bidirectional bubble sort, in which the items are run through twice at the same time, one going from top to bottom and one going from bottom to top. The following code is an example of a bidirectional bubble sort with an added level of efficiency. This function assumes that after one iteration through the array the first and last elements are in the correct place. It therefore looks at the array minus these two values.

function bidirectionalBubbleSort($array){
 if(!$length = count($array)){
  return $array;
 };
 $start = -1;
 while($start < $length){
  ++$start;
  --$length;
  for($i= $start; $i < $length; ++$i){
   if($array[$i] > $array[$i + 1]){
    $temp = $array[$i];
    $array[$i] = $array[$i + 1];
    $array[$i + 1] = $temp;
   }
  }
  for($i = $length; --$i >= $start;){
   if($array[$i] > $array[$i + 1]){
    $temp = $array[$i];
    $array[$i] = $array[$i + 1];
    $array[$i + 1] = $temp;
   }
  }
 }
}

However, this still isn’t that efficient. To get another level of efficiency you would need to use a shell short. This works on a "divide and conquer" technique where groups of the array are looked at and sorted individually. Here is an example function.

function shellSort($array){
 if(!$length = count($array)){
  return $array;
 };
 $k = 0;
 $gap[0] = (int)($length/2);
 while($gap[$k]>1){
  $k++;
  $gap[$k] = (int)($gap[$k-1]/2);
 }
 
 for($i = 0; $i <= $k; $i++){
  $step = $gap[$i];
  for($j = $step; $j<$length; $j++){
   $temp = $array[$j];
   $p = $j-$step;
   while($p >= 0 && $temp < $array[$p]){
    $array[$p+$step] = $array[$p];
    $p = $p-$step;
   };
   $array[$p+$step] = $temp;
  };
 };
 return $array;
}

Although this doesn’t look like it is efficient it depends on the data you are sorting. In a best case scenario the data will be randomly placed throughout the array and the algorithm will therefore have a good efficiency. Worst case is when all of the data is sorted in the wrong direction before you try to sort it. However, it is worth using this function unless you know for sure that the worst case will happen all of the time. Tests with random number arrays show that this algorithm is a good choice over the bubble sorts.

I should mention another algorithm here called a quick sort. The function works by splitting the array into smaller and smaller pieces eventually merging the array back together again at the end. It does this by first finding a middle point and then spitting the array depending on if the current value is higher or lower than the middle value. It then recursively calls itself in order to do the same to each section of the array. Here is an example of a quick sort

function quickSort($array){
 if(!$length = count($array)){
  return $array;
 };
 
 $k = $array[0];
 $x = $y = array();
 
 for($i=1;$i<$length;$i++){
  if($array[$i] <= $k){
   $x[] = $array[$i];
  }else{
   $y[] = $array[$i];
  };
 };
 return array_merge(quickSort($x),array($k),quickSort($y));
}

As the name suggests it is a fast way of sorting, and it would be if we were not using PHP. Although this function is very much quicker in Java or C, it is a very slow function in PHP. This is because PHP doesn’t handle recursion all that well. In fact when trying to test this function it either timed out the script, or simply gave the following memory error.

Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 35 bytes) in C:\htdocs\test.php on line 130

This occurred when testing an array length of just 50 and happens because every time PHP recursively calls a function it adds that information to the stack. This error happens because that stack is full. So although quick sort is fast in other languages you should probably stick to a shell sort or something similar. At the very least you will need to use a function that doesn’t use recursion.

If you fancy writing your own sorting functions then you can use the following function to check your work.
function checkSort($array){
 if(!$length = count($array)){
  return true;
 };
 for($i = 0; $i < $length; $i++){
  if(isset($array[$i+1])){
   if($array[$i]>$array[$i+1]){
    return false;
   };
  };
 };
 return true;
}

You can test how long your algorithm takes to run by using the PHP benchmarking function.