3

I've already asked a similar question, but I need a different effect. The original question is here.


I have a simple array. The array length is always a square number. So 16, 25, 36 etc.

$array = array('1', '2', '3', '4' ... '25');

What I do, is arrange the array with HTML so that it looks like a block with even sides.

What I want to do, is sort the elements, so that when I pass the JSON encoded array to jQuery, it will iterate the array, fade in the current block, and so I'd get a circular animation. So I'd like to sort the array kind of like this

So my sorted array would look like

$sorted = array('1', '6', '11'', '16', '21', '22', '23' .. '13');

Is there way to do so?.. Thanks


Edit:

I'm trying to do this by creating matrix-like column/row arrays with this:

$side = 5;

$elems = $side*$side;
$array = range(1,$elems);

for($i=1; $i <= $side; $i++) {
   for($x=$i; $x <= $elems; $x=$x+$side) {
      $columns[$i][] = $x; 
   }
}

for($i=1, $y=1; $i <= $elems; $i=$i+$side, $y++) {
   for($x=$i; $x < $side+$i; $x++) {
      $rows[$y][] = $x;
   }
}

My next step is to go down the first column, at the end if it go right on the last elements column, at the end up on the last element etc.. If anyone has a better idea that would be great :)

Community
  • 1
  • 1
Matt
  • 1,139
  • 1
  • 11
  • 28
  • technically this has absolutely nothing to do with PHP. this is something you'd do purely in javascript, regardless of what PHP sends over. And whatever solution was provided in your original question would apply here as well, simply change how your iterate the array. – Marc B Mar 04 '13 at 14:12
  • I'm not sure what the actual question is. Are you asking people to write you the jQuery code for this fairly complex animation?! – millimoose Mar 04 '13 at 14:13
  • @millimoose - A bunch of people were really quick to respond to a similar question. So I guess for some people this stuff is easier and they have no problems doing this type of sort/algorithm function. I'm trying, but keep failing. My code gets long, slow and buggy.. – Matt Mar 04 '13 at 14:15
  • 2
    This could be solved in similar manner to the previous one. The basic idea is to splice your original 'linear' array into actual two-dimensional 'square' array. Then just traverse it using array indices to establish order of elements – Mchl Mar 04 '13 at 14:18
  • @Matt The problem is your question is all over the place, and it's not clear what it is you're asking. If all you want is the sort algorithm, don't even mention jQuery and animations and whatever, just give example input and output for the desired question. Then watch your question get closed because you haven't shown any code you've tried or described the problems you're having with it. (Your original question was also low quality in that respect and having it answered was a fluke.) – millimoose Mar 04 '13 at 14:18
  • Personally, my approach would be to head off off-by-one errors, avoid and just use a 2D array of booleans to see whether I've "visited" a field. Then start in the top-left corner, go downwards marking fields as "visited" until you hit an edge or a previously "visited" field. Then go leftwards, doing the same, then turn upwards, etc. When the first field you'd visit after a direction change is visited, stop. As you go, store the coordinates of each field you pass in a "coordinate list". Then your end result will be the numbers from the original square, picked out according to those coordinates. – millimoose Mar 04 '13 at 14:22
  • Something worth considering but you could also ask this on Code Golf. It wouldn't be duplicate because the criteria for Code Golf answers are a lot different but it would a welcome challenge :) – Adam Elsodaney Mar 04 '13 at 14:26
  • As with my first question, I had trouble making an algorithm that would actually "move" around the grid, I just keep messing up the movement. – Matt Mar 04 '13 at 14:26
  • @Matt Don't provide vague prose descriptions. Provide **code**. Tell us where the code goes wrong. Tell us by saying what the various variable values are at the point where it goes wrong, and what you want them to be. Don't tell us "I can't do this someone else do this for me." – millimoose Mar 04 '13 at 14:31
  • I've added what I have now, that is part of the process – Matt Mar 04 '13 at 15:00
  • "If anyone has a better idea that would be great" - that's not really a valid SO question. Is there a specific problem with the code you have, besides "it's not done?" – millimoose Mar 04 '13 at 15:25

4 Answers4

1

This will work as long as the grid is always square:

<?php

    // The size of the grid - 5x5 in the example above
    $gridSize = 5;

    // Create a 2D array representing the grid
    $elements = array_chunk(range(1, pow($gridSize, 2)), $gridSize);

    // Find the half way point - this will be the end of the loop since we
    // want to stop in the middle
    $end = ceil($gridSize / 2);

    // An array to hold the result    
    $result = array();

    // The stopping point of the current interation
    $stop = $gridSize;

    // Loop from start to the middle
    for ($i = 0; $i < $end; $i++) {

        // start in the top left corner
        $x = $y = $i;

        // Traverse Y top to bottom
        while ($y < $stop) {
            $result[] = $elements[$y++][$x];
        }
        $y--;
        $x++;

        // Traverse X left to right
        while ($x < $stop) {
            $result[] = $elements[$y][$x++];
        }
        $x--;
        $y--;

        // Traverse Y bottom to top
        while ($y >= $gridSize - $stop) {
            $result[] = $elements[$y--][$x];
        }
        $y++;
        $x--;

        // Make sure we come in a level
        $stop--;

        // Traverse X right to left
        while ($x >= $gridSize - $stop) {
            $result[] = $elements[$y][$x--];
        }
    }

    print_r($result);

See it working

DaveRandom
  • 87,921
  • 11
  • 154
  • 174
0

This should work. You can pass any array to circularSort function and it will return your sorted array.

/*
Get the circular sorted array
*/
function circularSort($array)
{
    //Get the length of array
    $arrayLength = count($array);
    //Find the square root of length of array
    $arrayRows = sqrt($arrayLength);

    //Divide the arrays in $arrayRows
    $arrayChunks = array_chunk($array,$arrayRows);
    $circularArray = array();

    //Call Circular Array function .. Result will be stored in $circularArray
    circularArray($arrayChunks,$circularArray);
    return $circularArray;
}

/*
Loop arrayChunk in following order
1. Fetch first item from each chunks
2. Fetch all items from last chunk and remove that array from arrayChunk
3. Reverse elements in each remaining chunk
4. Reverse entire arrayChunk array
5. Repeat above 4 steps until $arrayChunks is empty
*/
function circularArray(&$arrayChunks, &$circularArray)
{
    if(empty($arrayChunks))
    {
        return true;
    }

    //1. Fetch first item from each chunks
    foreach($arrayChunks as &$arrayChunk)
    {
        $circularArray[] = array_shift($arrayChunk);
    }

    //Fetch Last Chunk from array
    $lastChunk = array_pop($arrayChunks);

    //2. Fetch all items from last chunk and remove that array from arrayChunk
    foreach($lastChunk as $chunkElement)
    {
        $circularArray[] = $chunkElement;
    }

    //3. Reverse elements in each remaining chunk
    foreach($arrayChunks as &$arrayChunk)
    {  
        if (is_array($arrayChunk))
        {    
            $arrayChunk = array_reverse($arrayChunk);
        }
    }

    $arrayChunks = array_reverse($arrayChunks);

    return circularArray(&$arrayChunks, &$circularArray);
}

e.g.

$array = range(1, 25);
$circularArray = circularSort($array);
Shahzad Malik
  • 541
  • 4
  • 6
0

Another approach in O(n):

<?php
function circ_sort ($inArray) {

    $rowSize = pow(count($inArray), 0.5);
    if((int)$rowSize != $rowSize) {
        throw new InvalidArgumentException();
    }
    $rowSize = (int)$rowSize;

    $round =-1;
    for ($x =-1, $y=0, $count =0; $count < count($inArray);) {

        if ($y > $x) {
            if ($x +1 == $y) {
                $direction = 'D';   //Down
                $round ++;
                $max_iter = $rowSize - (2 * $round);
            } else {
                $direction = 'L'; //Left
                $max_iter = $y - $x -1;
            }
        } else if ($x > $y) {
            $direction = 'R'; //Right
            $max_iter = $rowSize - (2 * $round) -1;

        } else if ($x == $y) {
            $direction = 'U'; //Up
            $max_iter = $rowSize - (2 * $round) -1;

        }

        switch ($direction) {
            case 'D':   //Down
                for ($iter =0; $iter < $max_iter; $iter++) {
                    $x++;
                    $circArray[] = $inArray[$x*$rowSize + $y];
                    $count++;
                }
                break;
            case 'R': //Right
                for ($iter =0; $iter < $max_iter; $iter++) {
                    $y++;
                    $circArray[] = $inArray[$x*$rowSize + $y];
                    $count++;
                }
                break;
            case 'U':   //Up
                for ($iter =0; $iter < $max_iter; $iter++) {
                    $x--;
                    $circArray[] = $inArray[$x*$rowSize + $y];
                    $count++;
                }
                break;
            case 'L':   //Left
                for ($iter =0; $iter < $max_iter; $iter++) {
                    $y--;
                    $circArray[] = $inArray[$x*$rowSize + $y];
                    $count++;
                }
                break;
        }
    }
    return ($circArray);
}

$array = range(1, 25);
$circ_array = circ_sort($array);

var_dump($circ_array);

?>
जलजनक
  • 3,072
  • 2
  • 24
  • 30
0

My solution:

The trick is: The first run is 5 then two runs of 4 elements, two of 3 elements, 2 of 2 elements and two of 1 element. (5,4,4,3,3,2,2,1,1) In each run it is incremented a state module 4. Depending on the state the runs goes in one direction or other.

Here is the code:

function circularSort(array $array) {
    $n2=count($array);
    $n=sqrt($n2);
    if((int)$n != $n) throw new InvalidArgumentException();

    $Result = Array();
    $run =$n; $dir=1;
    $x=0; $y=-1;
    $i=0;
    $st=0;
    while ($run) {
        while ($dir) {
            for ($j=0; $j<$run; $j++) {

                if ($st==0) $y++;
                if ($st==1) $x++;
                if ($st==2) $y--;
                if ($st==3) $x--;

                $p=$y * $n +$x;
                array_push($Result,$array[$p]);

            }
            $st = ($st +1) & 3;
            $dir--;
        }

        $dir=2;
        $run--;
    } 

    return $Result;
}

$a = range(1,25);
var_dump(circularSort($a));
jbaylina
  • 4,408
  • 1
  • 30
  • 39