views:

61

answers:

3

Hey,

I'm trying to figure out how to re-arrange a string using every x position so that an example input string of "ABCDEFGHI" and the x being 4 would yield DHCIFEGBA. Here's how I got that:

The 1st letter is easy: it's character 4. [A, B, C, D]
The 2nd letter is also easy: it's character 8. [E, F, G, H]
The 3rd letter is mostly easy: it's character 3. This happens because I looped around as I counted, so I used I, A, B, C.
The 4th letter is where things get trickier: It's character 9. Because D and H are already gone, they don't get used in the count, resulting in E, F, G, I.
Letter #5 follows the same pattern, skipping C and D: A, B, E, F
Letter #6 has skips AND a wrap: G, A, B, E.
Letter #7 wraps again: G, A, B, G.
Letter #8 also wraps (technically twice since 'cursor' was behind G before: A, B, A, B
Letter #9 is our remainder: A, A, A, A


It's clearly going to need to loop until output string length matches input string length - it's all of this mess in the middle (Mostly the skips and loops) that I can't for the life of me figure out.

Any help or guidance is appreciated.

A: 

I would try like this, though I haven't tested the code, yet:

$s = 'ABCDEFGHI';
$out = '';

While strlen($s) > 0 {
    $pos = 4 % strlen($s);
    $out += $s[$pos];
    if (strlen($s) > 3) $end = 3;
    else $end = strlen($s) - 1;
    $s = substr($s, 4, strlen($s)) + substr($s, 0, $end);
}

echo $out;
JochenJung
Thanks, Jochen. That's actually pretty similar to what I first tried. It only works until $s is down to 3 characters, then it fails and infinite loops out.
Zach R
+2  A: 

works perfectly with an unique range but will fail with something like ABCDEAFGHAI

$s = 'ABCDEFGHI';
$_len = strlen($s);
$out = '';
$c = 3;
echo '<pre>';
while ( $_len > 0 ) {
    echo strlen($s) ,  ' :: '.  $s . "\n";
    $term = $s[$c-1];
    list($a,$b) = explode($term, $s);
    $s = $b.$a;
    $x = strlen($s);
    if($x <= $c) {
        for($i=0; $i<($c-$x);$i++)
            $s .= $s;
    }

    $out .= $term;
    $_len--;
}

echo "\n\n\n" , $out;

output:

9 :: ABCDEFGHI
8 :: EFGHIABC
7 :: IABCEFG
6 :: EFGIAB
5 :: ABEFG
4 :: GABE
6 :: GABGAB
4 :: ABAB
4 :: AAAA

DHCIFEGBA

a hopefully better solution

function rearrangeString($string, $step = 4) {
    $output = '';
    $lenght = strlen($string);

    if($step >= $lenght) {
        return strrev($string);
    } elseif($step < 1) {
        return $string;
    } else {
        for($i=0; $i < $lenght; $i++) {
            $_tempLen = strlen($string);

            $output .= $string[$step-1];

            list($a,$b) = explode($string[$step-1], $string);

            $string = $b . $a;

            $_tempLen = strlen($string);
            if($step > $_tempLen) {
                $string = str_repeat($string, $step-$_tempLen+1);
            }
            unset($_tempLen, $a, $b);
        }

        return $output;
    }
}

$rearranged = rearrangeString('ABCDEFGHI');
var_dump($rearranged == 'DHCIFEGBA');

$rearranged = rearrangeString('ABCDEFGHI', 9);
var_dump($rearranged == 'IHGFEDCBA');

$rearranged = rearrangeString('ABCDEFGHI', 1);
var_dump($rearranged == 'ABCDEFGHI');

$rearranged = rearrangeString('ABCDEFGHI', 3);
var_dump($rearranged == 'CFIDHEBGA');

$rearranged = rearrangeString('ABCDEFGHI', 6);
var_dump($rearranged == 'FCAIBEHD');

$rearranged = rearrangeString('FARBE', 2);
var_dump($rearranged == 'ABFER');
maggie
Looks great - I'm assuming I should be able to replace the 4 with a variable (Say, $count) and then the 3 with a $count-1 and it would keep working?
Zach R
yes it should without an issue
maggie
Great job , +1.
M42
Works great, most of the time. Thanks! Setting $c to 6 or higher breaks it, though.
Zach R
A: 

Should work with any $s and $n

  <?php
    $s = "ABCDEFGHI";
    $n = 4;

    for ($i=0,$l=strlen($s) ; $l ; $l--)
    {
       $i = ($i+$n-1) % $l;
       echo $s[$i];
       $s = ($i ? substr($s, 0, $i) : '') . ($i < $l-1 ? substr($s, $i+1) : '');
    }
    echo "\n";
  ?>
ring0
Seems far more compact than the other solution, thanks. :)
Zach R