Amykate
Amykate

Reputation: 515

Array with variable number of elements, counting up

I want an multidimensional array, where each element is an array of X elements - lets say 3.

I basically want to count from 0 to y (lets say 12) in the 3rd element, then after 0,0,12 I want the next element in the array to be the array 0,1,0 - finished with 12,12,12.

I'm sort of counting up in base...12, ticking over to the next element in the array when it's done.

e.g.

0,0,0
0,0,1
...
0,0,12
0,1,0
0,1,1
0,1,2
...
0,1,12
0,2,0
...
12,12,12

ok, fine - I can do that like this

$maxCountNumber= 12;
$i=1;
for ($j=0; $j < $maxCountNumber+1; $j++) { 
    for ($k=0; $k < $maxCountNumber+1; $k++) { 
        for ($l=0; $l < $maxCountNumber+1; $l++) { 
                print "<br/>$i: $j, $k, $l";
                $results[$i] = array($j, $k, $l);
                $i++;
        }
    }
}

But what if I don't want just 3 elements every-time - sometimes i'll want 4 - Rather than hundreds, tens and units I want Thousands, Hundreds, tens and units... or how about 7 elements?

I'm sure recursion is the answer but I just can't seem to bend my head around this particular problem.

Unless there's something that will count up for me in 12s rather than 10s?

Thank you for all and any advice.

Upvotes: 3

Views: 506

Answers (3)

aleation
aleation

Reputation: 4844

This algorithm precalculates the number of loops needed in total, then use $i to calculate each array position's value.

$max= 13;
$elements = 4;
$loops = pow($max, $elements);

$main_array = array();

for($i = 0; $i < $loops; $i++){
    for($j = 0; $j < $elements; $j++){
        $main_array[$i][$j] = floor($i/pow($max,$elements-1-$j))%$max;
    }
}

This is the most elegant solution I found, just 2 nested loops with 1 arithmetic operation using power and modulus to get the desired array each time.

You just have to adjust the elements and/or the base number.

took 0.014s to calculate the array with 3 positions.

took 0.25s to calculate the array with 4 positions.

took 4.08s to calculate the array with 5 positions*

*for 5 positions I needed to increase the memory_limit, I guess because the array gets too big, this script would be much lighter if you did just the output of the numbers instead of storing a huge array.

Upvotes: 2

Refugnic Eternium
Refugnic Eternium

Reputation: 4291

Okay now, let's see...

$numberOfDimensions = 3;
$base = 13;

$YourArray = array();    //This array will hold the complete data.
$LastArray = array();
for($o = 0; $o < $numberOfDimensions; ++$o) //Gives us something to start with.
    $LastArray[$o] = 0;    

while($LastArray[0] < $base) {      //Makes sure, we're not going out of bounds
    $index = $numberOfDimensions - 1;
    $YourArray[] = $LastArray;      //Adds the array you filled last to the result array.
    while($index >= 0) {            //This is where things start to get interesting.
        if(++$LastArray[$index] < $base) break;  //Still in bounds, continue.
        else {
            if($index)              //Overflow for all but the first element..
                $LastArray[$index] = 0;
            --$index;               //Moving on to the previous digit.
        }
    }
}

echo "<pre>";
echo print_r($YourArray);
echo "</pre>";

Phew...that was more difficult on my tired brain than I thought when I read the question. This should work...if you have questions regarding the code, feel free to ask.

I've tested it now, and it does what is to be expected. During my tests I encountered a foolish error, which is hereby fixed. Sorry for the delay.

Upvotes: 2

Nathaniel Ford
Nathaniel Ford

Reputation: 21220

Your basic recursion is as follows:

<?php 
class StrangeBase { 
  private static function loopOnStrangeBase($place, $base, $printstr) { 
    if (($place < 0) || ($base < 0)){ return; }//edge case 
    for ($idx=0; $idx<$base; $idx++) { 
      if ($place == 0) { 
        echo "$printstr,$idx\n"; 
      } else {
        if($printStr !== ''){ 
          StrangeBase::loopOnStrangeBase($place - 1, $base, $printstr.",$idx");
        } else {
          StrangeBase::loopOnStrangeBase($place - 1, $base, "$idx");
        }
      }
    } 
  }

  public static function printStrangeBase($places, $base) {
    StrangeBase::loopOnStrangeBase($places, $base, "");
  }
} 

StrangeBase::printStrangeBase(3, 12); 

Now, you can modify this to not be static functions, but rather also save out to an array. To do this, your array should grow 'backwards'; that is the first element in the array is the lowest-order place in your number. You can then further modify the recursive function to take a function pointer and run arbitrary code rather than simply print out where it is.

Upvotes: 0

Related Questions