7

Is there a way to perform sorting on integers or strings in an instance of the SplFixedArray class? Is converting to a PHP's array, sorting, and then converting back being the only option?

Desmond Hume
  • 8,037
  • 14
  • 65
  • 112
  • 2
    Yes. PHPs native sorting functions do not work on object arrays. You need said workaround, or some manual coding: http://phppowercoding.com/the-speed-issue-or-alternately-why-a-php-implemented-quicksorts-not-so-quick/397 – mario Jul 21 '13 at 15:07

2 Answers2

4

Firstly, congratulations on finding and using SplFixedArrays! I think they're a highly under-utilised feature in vanilla PHP ...

As you've probably appreciated, their performance is unrivalled (compared to the usual PHP arrays) - but this does come at some trade-offs, including a lack of PHP functions to sort them (which is a shame)!

Implementing your own bubble-sort is a relatively easy and efficient solution. Just iterate through, looking at each consecutive pairs of elements, putting the highest on the right. Rinse and repeat until the array is sorted:

<?php
$arr = new SplFixedArray(10);
$arr[0] = 2345;
$arr[1] = 314;
$arr[2] = 3666;
$arr[3] = 93;
$arr[4] = 7542;
$arr[5] = 4253;
$arr[6] = 2343;
$arr[7] = 32;
$arr[8] = 6324;
$arr[9] = 1;

$moved = 0;
while ($moved < sizeof($arr) - 1) {
    $i = 0;
    while ($i < sizeof($arr) - 1 - $moved) {
        if ($arr[$i] > $arr[$i + 1]) {
            $tmp = $arr[$i + 1];
            $arr[$i + 1] = $arr[$i];
            $arr[$i] = $tmp;
        }
        $i++;

        var_dump ($arr);
    }
    $moved++;
}

It's not fast, it's not efficient. For that you might consider Quicksort - there's documented examples online including this one at wikibooks.org (will need modification of to work with SplFixedArrays).

Seriously, beyond getting your question answered, I truly feel that forcing yourself to ask why things like SplFixedArray exist and forcing yourself to understand what goes on behind a "quick call to array_sort()" (and why it quickly takes a very long time to run) make the difference between programmers and programmers. I applaud your question!

wally
  • 3,492
  • 25
  • 31
  • 1
    Blindly using bubble sort for `SplFixedArray` might be worth idea that eliminates all benefits of using fixed array as itself. Just check how many cases [are covered](https://github.com/php/php-src/blob/250938e2d35fc54161a18167b7901c5e3b574371/Zend/zend_sort.c) by php by itself (well, in 7.x branch). – mente Nov 10 '15 at 09:51
  • I implemented a Quicksort on an SplFixedArray once to figure out what the performance hit would be. While I did my best to optimize the algorithm, the entire experiment fell short solely due the overhead of PHP itself. – Flosculus Jan 25 '16 at 10:16
  • @Flosculus - would you be willing to post the code here, or in pastebin or something? I'd be really interested to see what you did - and see your performance results. – wally Jan 25 '16 at 10:33
  • @wally I don't have it any more, but I may write it again since I'm currently looking for ways to create a `Vector` using `SplFixedArray`. FYI though, I used Java's quicksort algorithm to learn how it works: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/Arrays.java#Arrays.sort1%28int[]%2Cint%2Cint%29. It took me ages to read it however ... – Flosculus Jan 25 '16 at 10:54
2

Here's my adaptation of bubble sort using splFixedArrays. In PHP 7 this simple program is twice as fast as the regular bubblesort

function bubbleSort(SplFixedArray $a) 
{
   $len = $a->getSize() - 1;
   $sorted = false;

   while (!$sorted) {
    $sorted = true;
    for ($i = 0; $i < $len; $i++)
    {
        $current = $a->offsetGet($i);
        $next = $a->offsetGet($i + 1);

        if ( $next < $current ) {
            $a->offsetSet($i, $next);
            $a->offsetSet($i + 1, $current);
            $sorted = false;
        }
    }
  }

  return $a
}

$starttime = microtime(true);
$array = SplFixedArray::fromArray([3,4,1,3,5,1,92,2,4124,424,52,12]);
$array = bubbleSort($array);

print_r($array->toArray());
echo (microtime(true) - $starttime) * 1000, PHP_EOL;
Kearney Taaffe
  • 647
  • 8
  • 20