0

Swap-up element in a multidimensional array with the sibling above it.

I want the element with the selected index in the array to swap it's position with the one above him.

  1. The element from it's position(N) to go to position(N-1)
  2. I want the element at position(N-1) to go at position(N),
  3. The resulting index should be reflecting correctly their new order in the array. array_values($tmparr); does sort the index correctly
  4. The Target Element to swap up can go to Position(0) but will never start at Position(0)
  5. The Element to swap down if at Position(0) Should go at position(1) not go at the End of the array.

Although this function explain semantically what i want to do it does not work at all.

function swaparray($tmparr,$posa,$posb){
 $vala = $tmparr[$posa];
 $valb = $tmparr[$posb];
 $tmparr[$posa] = $valb;
 $tmparr[$posb] = $vala;
 return $tmparr; }

The 2nd function shifts the intended target up but the above element is pushed up and goes to the end of the list if he is at position 0, it does not go under the target, so it doesnt work as intended it

 function swaparray($tmparr,$posa,$posb){
  $vala = $tmparr[$posa];
  $valb = $tmparr[$posb];
  unset($tmparr[$posa]);
  unset($tmparr[$posb]);
  $tmparr[$posa] = $valb;
  $tmparr[$posb] = $vala;
  $tmparr = array_values($tmparr);
 return $tmparr;
}

Reading further about my issue is seams Array_splice() could do the trick. What are your inputs about this?

Edit Answer: (PHP >= 4.3.8 )

The working solution with Array_splice()

 function swaparray($array, $n) {
     // taking out at $n
     $out = array_splice($array, $n, 1);
     // adding in at $n - 1
    array_splice($array, $n - 1, 0, $out);
    return $array;
 }

Here is the original multidimensional array

 Array ( [0] => Array ( [key1] => 1 [key2] => 1 [key3] => 1 [key4] => 1 )
         [1] => Array ( [key1] => 2 [key2] => 2 [key3] => 2 [key4] => 2 ) 
         [2] => Array ( [key1] => 3 [key2] => 3 [key3] => 3 [key4] => 3 ) 
         [3] => Array ( [key1] => 4 [key2] => 4 [key3] => 4 [key4] => 4 ) )

Here is an excerpt / exemple of want i wanted it to do.

[0] key1=1 key2=1 key3=1 key4=1
[1] key1=2 key2=2 key3=2 key4=2 
[2] key1=3 key2=3 key3=3 key4=3 <- 
[3] key1=4 key2=4 key3=4 key4=4

swaparray($tmparr,2);

[0] key1=1 key2=1 key3=1 key4=1
[1] key1=3 key2=3 key3=3 key4=3 <- 
[2] key1=2 key2=2 key3=2 key4=2 
[3] key1=4 key2=4 key3=4 key4=4     

swaparray($tmparr,1);

[0] key1=3 key2=3 key3=3 key4=3 <- 
[1] key1=1 key2=1 key3=1 key4=1
[2] key1=2 key2=2 key3=2 key4=2 
[3] key1=4 key2=4 key3=4 key4=4 

swaparray($tmparr,1);

[0] key1=1 key2=1 key3=1 key4=1 <-
[1] key1=3 key2=3 key3=3 key4=3  
[2] key1=2 key2=2 key3=2 key4=2 
[3] key1=4 key2=4 key3=4 key4=4 
GuruJR
  • 336
  • 1
  • 10
  • @hakre - true the array_splice implementation is tricky so far, as for the original, i could reword it , but i can't really make it more simple. – GuruJR Oct 06 '12 at 17:22
  • @hakre your sugestion of moveElement renamed to swaparray didnt worked with the multidimensional / associative-array. – GuruJR Oct 06 '12 at 17:37
  • PHP 4.3.8 is too localized! [Quoting GuruJR:](http://stackoverflow.com/questions/12761782/array-splice-to-swap-an-element-with-previous-in-a-multidimensional-associative/12762142#comment17245289_12762142) *"It need to work on php4, ill check wich iteration edit : PHP/4.3.8"*. – hakre Oct 06 '12 at 17:58
  • @hakre Thank you, it was what i was looking for, has i tough Array_splice() was the way to go, thanks for pointing me in the right direction. i just had to bare bone your implementation a bit. – GuruJR Oct 06 '12 at 18:52

3 Answers3

2

The element from it's position(N) to go to position(N-1) I want the element at position(N-1) to go at position(N),

All you say is that you want to swap the two, where N is never 0 in a zero indexed array.

Move Element N to N-1:

/** 
  * [0] is top
  */
function moveUp(&$array, $n) {
    if ($n < 1)             throw new InvalidArgumentException();
    if (!isset($array[$n])) throw new InvalidArgumentException();
    // taking out at $n
    $out = array_splice($array, $n, 1);
    // adding in at $n - 1
    array_splice($array, $n - 1, 0, $out);
}

Usage:

$n = 2;
moveUp($array, $n);
var_dump($array);

Because the element at N-1 will get one element added in front, it will automatically move to N. Job done. array_splice is really powerful.

hakre
  • 193,403
  • 52
  • 435
  • 836
  • +1 Nice code... but you think this is simpler than storing and reassigning array values? :) – Pebbl Oct 06 '12 at 17:42
  • @hakre -Parse error: parse error, unexpected T_NEW on line 1 – GuruJR Oct 06 '12 at 17:45
  • @hakre- i want to move N to N-1, and N-1 to N , So the one that was below goes over , and if 0 be the first, but the first one to go down to index 1, not to the bottom, i think you understood. – GuruJR Oct 06 '12 at 17:47
  • @pebbl - but the simple move dont work , for an unknow reason. probably php4 voodoo – GuruJR Oct 06 '12 at 17:48
  • 1
    Guru, which PHP version are you using? – hakre Oct 06 '12 at 17:49
  • 1
    It need to work on php4, ill check wich iteration edit : PHP/4.3.8 – GuruJR Oct 06 '12 at 17:50
  • 1
    well, if you pay extra I will support you that, this does not belong on this site. PHP 4 is EOL, no free support here. – hakre Oct 06 '12 at 17:56
  • @hakre thx for the help, when ill get the fix ill let you know. – GuruJR Oct 06 '12 at 18:06
  • 1
    @hakre stringed it for oldschool server but it worked. ill add the fix to my question. – GuruJR Oct 06 '12 at 18:35
  • @GuruJR: yeah, easy, wasn't it? ;) – hakre Oct 06 '12 at 19:02
  • @hakre your were right on, The obvious solutions weren't working. Like you said array_splice() is really powerful and it hasn't changed since php4 but it was daunting to tackle after a whole night, of not getting the simple array swap working. That's why i came here to ask. At last thx. – GuruJR Oct 06 '12 at 19:16
  • Yes, that can happen when fiddling too long with the same problem. – hakre Oct 06 '12 at 19:19
0

This looks complex at first but its just basic variable swapping and retaining the key. What you need is to Reference with & in your function

$array = Array ( 
"0" => Array ( "key1" => 1 , "key2" => 1 , "key3" => 1 , "key4" => 1 ),
"1" => Array ( "key1" => 2 , "key2" => 2 , "key3" => 2 , "key4" => 2 ) ,
"2" => Array ( "key1" => 3 , "key2" => 3 , "key3" => 3 , "key4" => 3 ) ,
"3" => Array ( "key1" => 4 , "key2" => 4 , "key3" => 4 , "key4" => 4 ) );

swaparray($array,2,1);
var_dump($array);

Output

array
  0 => 
    array
      'key1' => int 1
      'key2' => int 1
      'key3' => int 1
      'key4' => int 1
  1 => 
    array
      'key1' => int 3
      'key2' => int 3
      'key3' => int 3
      'key4' => int 3
  2 => 
    array
      'key1' => int 2
      'key2' => int 2
      'key3' => int 2
      'key4' => int 2
  3 => 
    array
      'key1' => int 4
      'key2' => int 4
      'key3' => int 4
      'key4' => int 4

If you run it 3 times swaparray

swaparray($array,2,1);
swaparray($array,1,0);
swaparray($array,1,0);

var_dump($array);

YOu would get

array
  0 => 
    array
      'key1' => int 1
      'key2' => int 1
      'key3' => int 1
      'key4' => int 1
  1 => 
    array
      'key1' => int 3
      'key2' => int 3
      'key3' => int 3
      'key4' => int 3
  2 => 
    array
      'key1' => int 2
      'key2' => int 2
      'key3' => int 2
      'key4' => int 2
  3 => 
    array
      'key1' => int 4
      'key2' => int 4
      'key3' => int 4
      'key4' => int 4

Function Used

function swaparray(&$array, $originKey, $destinationKey) {
    $origin = isset($array[$originKey]) ? $array[$originKey] : false;
    $destination = isset($array[$destinationKey]) ? $array[$destinationKey] : false;

    if ($origin && $destination) {
        $array[$originKey] = $destination;
        $array[$destinationKey] = $origin;
        return true;
    }
    return false;
}
Baba
  • 94,024
  • 28
  • 166
  • 217
  • just tried it, does not work on my side, it gives me the same result has with my first function, nothing moves. – GuruJR Oct 06 '12 at 17:04
  • @GuruJR look at a live test http://codepad.org/uqgYQ1J5 – Baba Oct 06 '12 at 17:09
  • @GuruJR Example running 3 diffrent swap on the same array http://codepad.org/JaKAsG5F – Baba Oct 06 '12 at 17:12
  • @Baba- i know i tried it, it does not work under that server, even with the variable passed by reference. You've just reworded the function i was saying is not working,The array is just not moving. It Stays the same, ill try your edit but so far i get the same result i was getting with the troublesome function. – GuruJR Oct 06 '12 at 17:17
  • @GuruJR what is the server specification , also add `error_reporting(E_ALL)` and `ini_set("display_error","On")` on top of your script – Baba Oct 06 '12 at 17:20
  • @hakre have improved on the function – Baba Oct 06 '12 at 17:28
  • on that server it's php4, error_reporting(E_ALL) & ini_set("display_error","On") -> no error reported – GuruJR Oct 06 '12 at 17:29
  • @Baba - on the original i wasnt passing the reference , only in your version does the reference get passed. – GuruJR Oct 06 '12 at 17:30
  • @baba ill try that new version – GuruJR Oct 06 '12 at 17:36
  • @GuruJR ... Works perfectly on PHP4 http://sandbox.onlinephpfunctions.com/code/a8c9e2b21123c0f226311cf5a6be289097b63020 – Baba Oct 06 '12 at 17:51
0

A quick simple version that should do pretty much what you want - just the same as all the other options on this page - I'm especially surprised that your own first function doesn't do what you need either? As far as I can see it should work perfectly... the only difference being is that it doesn't pass by reference.

function moveUp2(&$array, $n){
  if ( $n && array_key_exists($n, $array) ) {
    list( $array[$n-1], $array[$n] ) = array( $array[$n], $array[$n-1] );
  }
}

/// example usage
moveUp2( $array, 1 );

echo '<xmp>';
print_r($array);
echo '</xmp>';

Now obviously the above function assumes you are using numeric keys and that all keys in the array are in sequence - if for example you had keys proceeding like 0,1,3,4 -- then shifting 3 would mean that the value placed at 2 would appear at the end of the array...

If you find that array referencing is causing issues, just remove the & in the argument list and make sure the function returns $array. This would mean the example usage would change though, obviously:

/// example usage
$array = moveUp2( $array, 1 );

echo '<xmp>';
print_r($array);
echo '</xmp>';
Pebbl
  • 34,937
  • 6
  • 62
  • 64
  • I know the original function should had worked in the first place, but some version of php drop the ball on array manipulation. If you get in a place where the basic array[key1] = array[key2] assignment don't work. Try this nice hack. – GuruJR Oct 06 '12 at 18:55
  • heh, I have no idea what versions of php you've experienced :S but I've been working with php since v2 and never had any problem with arrays doing unexpected things... One thing that you might've had to watch out for would've been the difference between `array['1']` and `array[1]` but aside from that I have no idea what would cause such an issue. goodluck with it though. – Pebbl Oct 06 '12 at 19:04