6

Been checking out other ways used to order array values vertically for use in a table but most of them were the equivalent of flipping your table 90 deg to the right. I've been trying to think of a way to properly implement this but I think I need some help.

For example, the table (horizontal order):

a  b  c  d  e
f  g  h  i  j
k  l  m  n  o
p  q  r

Is reordered to (vertical order):

a  e  i  m  p
b  f  j  n  q
c  g  k  o  r
d  h  l   

As you can see the structure is retained since the last 2 cells are empty.

Not like this:

a  e  i  m  q
b  f  j  n  r
c  g  k  o
d  h  l  p

In this example, the table is akin to flipping it sideways. Does anyone know how to properly do this?

mickmackusa
  • 43,625
  • 12
  • 83
  • 136
enchance
  • 29,075
  • 35
  • 87
  • 127

3 Answers3

2

EDITED: This is harder than I thought and I messed it up the first time (or two). It should work now.

Let's say you have your table structure stored in a two dimensional array:

$data = array(
  array('a', 'b', 'c', 'd', 'e'),
  array('f', 'g', 'h', 'i', 'j'),
  array('k', 'l', 'm', 'n', 'o'),
  array('p', 'q', 'r')
);

Since you want to keep the same "shape" you need to determine the dimensions of the table. To do this we can take the count of the first row, since we know that the first row must be the maximum width of the table. The height is just the number of elements in the array.

$width = count($data[0]); // 5
$height = count($data);   // 4

We also need the total number of elements, but we can overestimate by taking $width * $height.

$total = $width * $height; // 20

Then it's really just a little math to calculate where things go. We have to use a separate counter for the old and new indices because we will have to increment them differently once we start to have holes.

$new_data = array();
$j = 0;
for($i = 0; $i < $total; $i++) {
  $old_x = floor($i / $width); // integer division
  $old_y = $i % $width;        // modulo

  do {
    $new_x = $j % $height;        // modulo
    $new_y = floor($j / $height); // integer division
    $j++;
  // move on to the next position if we have reached an index that isn't available in the old data structure
  } while (!isset($data[$new_x][$new_y]) && $j < $total);

  if (!isset($new_data[$new_x])) {
    $new_data[$new_x] = array();
  }
  if (isset($data[$old_x][$old_y])) {
    $new_data[$new_x][$new_y] = $data[$old_x][$old_y];
  }
}
seanmk
  • 1,934
  • 15
  • 28
  • Oops, I didn't test it before I posted it the first time and I switched the width and height around. The post is fixed now. – seanmk Jul 23 '13 at 04:56
  • I tried it and it doesn't work. Your first row came out as `a e i m q` when it should be `a e i m p`. Since the first row is wrong then the rest of the rows moved as well. Also, rows 1-3 need to have 5 columns while in your example only rows 1-2 have 5 elements. – enchance Jul 23 '13 at 05:08
  • Okay I thought about this more and updated the answer. It should work now. – seanmk Jul 23 '13 at 05:59
  • The answer is still `O(n^2)` as you are looping through the total which is the width * height – Andy Jones Jul 24 '13 at 00:38
  • Sorry, I was never good in math but what's the `O` in `O(n^2)` and how does it fit this solution? – enchance Jul 24 '13 at 04:21
  • You are completely right @Andy. I confused myself here. The O is "big O notation": https://en.wikipedia.org/wiki/Big_O_notation. This thread has a good explanation: http://stackoverflow.com/questions/11032015/how-to-find-time-complexity-of-an-algorithm – seanmk Jul 24 '13 at 17:41
1

The trick is to subtract one for the "hanging" columns. That is the columns that have a value missing in the last row.

// setup some initial test data... rip this out and replace with whatever
$values = array();
for ($x = 0; $x < 18; ++$x)
  $values[] = chr($x + ord("a"));

We can arbitrarily change the number of columns. The number of rows is determines by the size of our data divided by the number of columns we use.

// change # of columns to desired value
$columns = 5;
$rows = (int) ceil(count($values) / $columns);

Some columns hang. That is the column is missing a value in the last row.

// the number of columns that will "hang" or miss a value in the last row
$hanging_columns = $columns * $rows - count($values);

$counter = 0;
for ($y = 0; $y < $rows; ++$y) {
  for ($x = 0; $x < $columns; ++$x) {
    // if we've displayed all values, stop
    if ($counter++ >= count($values)) break;

    // calculate the correct index to display
    $index = ($y + $x * $rows);
    // if we are in a hanging column, we need to back up by one
    if ($x > $columns - $hanging_columns) $index -= 1;

    // display the value
    echo $values[$index] . " ";
  }
  echo "\n";
}
Andy Jones
  • 6,205
  • 4
  • 31
  • 47
0

Here another solution

$unflipped = array('a', 'b', 'c', 'd', 'e', 
               'f', 'g', 'h', 'i', 'j',
               'k', 'l', 'm', 'n');


function flip90($arr, $lineHeight) 
{
    $tbl = array();

    $index = 0;
    $counter = 1;


    for($i = 0; $i < count($arr); $i++)
    {
        if($counter > $lineHeight)
        {
            $index++;
            $counter = 1;
        }

        if($counter <= $lineHeight) 
        {
            $tbl[$index][$counter] = $arr[$i];

            $counter++;
        }

    }

    return $tbl;
}

$flipped = flip90($unflipped, 5);
echo "<pre>";
var_dump($flipped);
echo "<pre>";

The function needs the array and the line height for dimensioning your table

Felix
  • 2,531
  • 14
  • 25