2

I have a simple string. I need to produce an output Array such that the order of every 2 consecutive characters is reversed.

Input string is 14f05000034e69 and I need the following output Array [4, 1, 0, f, 0, 5, 0, 0, 4, 3, 6, e, 9, 6].

Here is my PHP code:

$myString = "14f05000034e69";
$myStringArray = str_split($myString);

$newArray = array();
for ($index=0; $index<count($myStringArray)-1; $index+2) {
    $newArray[] = $myStringArray[$index+1];
    $newArray[] = $myStringArray[$index];
}

print_r($newArray);

And it is giving me

Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 134217736 bytes) in /var/www/html/test.php on line 8

The question is why and how do I fix it?

AymDev
  • 6,626
  • 4
  • 29
  • 52
Shy
  • 542
  • 8
  • 20
  • Possible duplicate of [Fatal Error: Allowed Memory Size of 134217728 Bytes Exhausted (CodeIgniter + XML-RPC)](https://stackoverflow.com/questions/561066/fatal-error-allowed-memory-size-of-134217728-bytes-exhausted-codeigniter-xml) – AymDev Aug 29 '18 at 09:21
  • 5
    You are not incrementing `$index`, so the loop goes on until eternity, filling `$newArray`. – Roman Hocke Aug 29 '18 at 09:21
  • 5
    this should be `for (declare; cond; $index+=2) {` – AymDev Aug 29 '18 at 09:23
  • I did by RegEx and probably would if it was me, since the pattern is quite simple, and less variables to write. – Rafael Aug 29 '18 at 10:18

4 Answers4

2
<?php


$myString = "14f05000034e69";
$myStringArray = str_split($myString);

$i=0;
foreach($myStringArray as $row){
    if(array_key_exists($i,$myStringArray)) {
        $newArray[$i] = $myStringArray[$i + 1];
        $newArray[$i + 1] = $myStringArray[$i];
        $i = $i + 2;
    }
}

echo '<pre>';
print_r($newArray);

I found a workaround in a bit "dirty" way but i managed to do what you asked.

Basically i split the string like you did but i play with the new array positions around and push in my new array the positions that i want to that's why i used a counter for that.

The output is:

Array
(
    [0] => 4
    [1] => 1
    [2] => 0
    [3] => f
    [4] => 0
    [5] => 5
    [6] => 0
    [7] => 0
    [8] => 3
    [9] => 0
    [10] => e
    [11] => 4
    [12] => 9
    [13] => 6
)

Basically i thought that i need to loop the array by two but every time i loop i need to handle 2 array positions and then the next two.

So that led me to handle my $new_array in a way that i push at the same time data in the current position i am and in the next position, that's why the counter $i+1 is used to handle array position.

If i did not use it there and used simple $newArray[] it would put the data in my current position and overwrite it again in the second step and also i could not move my array pointer to positions 1,3,5,6 etc etc that's why i am "forcing" it to use my $i counter so i keep pointing every after position.

My $i counter is set at the end of each loop to move with step 2.

pr1nc3
  • 8,108
  • 3
  • 23
  • 36
  • You don't even need to put $i or $i+1 in $new_array. $new_array[] is enought as you push reversed values. just as you don't need to reset $i each loop. You don't change it – Dice Aug 29 '18 at 09:33
  • yes but in the values that i push inside the new array i need to use my counter for the array i am having without being reversed that's why + i need to point my new array where to put the new data that's why my counter goes +2 and not +1 – pr1nc3 Aug 29 '18 at 09:34
  • But the $new_array[$i]/$new_array[$i+1] remains useless $new_array[] is enough – Dice Aug 29 '18 at 09:37
  • I will expand my explanation in my post for that cause i have to put it there but i will become more detailed why – pr1nc3 Aug 29 '18 at 09:38
  • Lokking forward to it – Dice Aug 29 '18 at 09:40
2

The shortest alternative I could come up with is to use some of the array methods instead...

$myString = "14f05000034e69";

$out = str_split(implode(array_map ('strrev', str_split($myString, 2))));

print_r( $out );

This uses str_split() to split it into 2 char chunks, then uses array_map() and strrev() to reverse each item and then implode() to put them all back again.

The outer call to str_split() just splits the result back down to 1 char elements in an array for the output (miss this off if you just need the string itself)

Nigel Ren
  • 56,122
  • 11
  • 43
  • 55
2

In my opinion, the str_split is redundant in this operation, strings can be iterated through as of arrays, like this:

$myString = "14f05000034e69";

$newArray = array();
for ($index=0; $index<strlen($myString)-1; $index+=2) 
{
    $newArray[] = $myString[$index+1];
    $newArray[] = $myString[$index];
}

print_r($newArray);

But yeah, as said before, just missing += in the for loop.

I made a small test on regex to see if it could be done, works as a charm. But of course, I only deliver a string in this case. :)

$myString = "14f05000034e69";

$test = preg_replace('/(.)(.)/', '$2$1', $myString);

echo $test;

This is the most elegant solution I could come up with.

Code tested here: https://3v4l.org/mtdca

And for the regex: https://3v4l.org/nI4UP

Rafael
  • 1,495
  • 1
  • 14
  • 25
2

An answer has already been marked as the solution an many other answers too however I think this can help to know that we can achieve the inversion in the string itself and then split it.If an array is not needed we can just keep the string.This way we use less memory i think:

    $myString = "14f05000034e69";
    $length=strlen($myString);
    for ($index=-1, $length=$length%2==0?$length-1:$length-2; $index<$length-1; $index+=2) {
        $tmp=$myString[$index+1];
        $myString[$index+1]=$myString[$index+2];
        $myString[$index+2]=$tmp;
    }


print_r(str_split($myString));// return an array 
print_r($myString); //here a string

This can handle variable length of strings

Elementary
  • 1,443
  • 1
  • 7
  • 17