stu96art has asked for the wisdom of the Perl Monks concerning the following question:

OK, this is a real easy question (I actually feel stupid asking it, but I could not find much in the Search, maybe I was looking for the wrong thing). Anyways I am just wanting to make sure this is working correctly. I want to swap two things  $blocks[$blockcount][4] and  $blocks[$blockcount][5] but my array is  $blocks[$blockcount][$vertexcount][$i] where $i = (0..6). Here is what I have
@temp = $blocks[$blockcount][4]; $blocks[$blockcount][4] = $blocks[$blockcount][5]; $blocks[$blockcount][5] = @temp;

Replies are listed 'Best First'.
Re: Swapping two values
by dws (Chancellor) on Feb 14, 2003 at 21:54 UTC
    To swap those two values, it suffices to do
    ($blocks[$blockcount][4], $blocks[$blockcount][5]) = ($blocks[$blockcount][5], $blocks[$blockcount[4]);
      @{$_}[4,5] = @{$_}[5,4] for $blocks[$blockcount];

      jdporter
      The 6th Rule of Perl Club is -- There is no Rule #6.

Re: Swapping two values
by sauoq (Abbot) on Feb 14, 2003 at 22:07 UTC

    Your code will work, but it exposes a misunderstanding that you have. There is no need to use an array, @temp, to store your array element, $blocks[$blockcount][4], because your array element is a scalar variable. In fact, all array elements are scalars. In your case, that scalar just happens to be a reference to another array.

    Your code works because it is simply using the first element of @temp as a temporary variable. This is what you meant to do:

    $temp = $blocks[$blockcount][4]; $blocks[$blockcount][4] = $blocks[$blockcount][5]; $blocks[$blockcount][5] = $temp;
    And that will be sufficient. You can also use the shorthand that dws suggested to swap values without a temporary variable.

    -sauoq
    "My two cents aren't worth a dime.";
    
Re: Swapping two values
by thelenm (Vicar) on Feb 14, 2003 at 22:01 UTC
    You can easily swap these values using array slices, maybe like this:
    @{$blocks[$blockcount]}[4,5] = @{$blocks[$blockcount]}[5,4];

    -- Mike

    --
    just,my${.02}

Re: Swapping two values
by integral (Hermit) on Feb 15, 2003 at 08:28 UTC

    In addition to the perl idiom of using a list assignment to swap values without a temporary variables, there is the idiom using the XOR operator. Although this does take three statements and doesn't fully take advantage of perl's list assignments, and so is more useful in other languages.

    $a ^= $b; $b = $a ^ $b; $a = $a ^ $b;

    Update:Here's a contracted form of the above:

    $a = $a ^ ($b = ($a ^= $b) ^ $b);

    --
    integral, resident of freenode's #perl
    

      As I've pointed out before, using XORs to swap values in perl will not work with references. (Note, by the way, that the OP was an inquiry about swapping references.)

      References aren't the only values this naive method will break on. Try it with $a = 1; $b = "0foo"; for instance.

      In C or assembly, you can swap values with bitwise XOR to avoid the use of temporary storage. It's rarely necessary, but comes in handy when you need things to be real fast and you have a limited number of registers. In such lower level languages, it works on strings because strings are pointers and pointers are ints and XOR works nicely on ints. In perl, however, the XOR method will do a bitwise XOR on the whole string. When all you want to do is swap values, that's grossly inefficient.

      Bitwise XOR should never be used to swap values in perl. It isn't maintainable. It isn't efficient. It isn't clever. Don't do it.

      -sauoq
      "My two cents aren't worth a dime.";
      
      While clever, it is wrong even in other languages if there is any possibility that $a and $b are the same (or overlap).

        In languages like C (and not Perl) where it sometimes makes sense to use this method for swapping values, it will work just fine even if the values are the same. I'm unsure what you mean by "overlap." To see that it will work, try it with all four combinations of 2 bits:

        A | B | A = A^B | B = A^B | A = A^B | A | B ===|===|=========|=========|=========|===|=== 0 | 0 | 0 = 0^0 | 0 = 0^0 | 0 = 0^0 | 0 | 0 ---+---+---------+---------+---------+---+--- 0 | 1 | 1 = 0^1 | 0 = 1^1 | 1 = 1^0 | 1 | 0 ---+---+---------+---------+---------+---+--- 1 | 0 | 1 = 1^0 | 1 = 1^0 | 0 = 1^1 | 0 | 1 ---+---+---------+---------+---------+---+--- 1 | 1 | 0 = 1^1 | 1 = 0^1 | 1 = 0^1 | 1 | 1
        See? It works fine even when the values are equal.

        But, don't do it in perl!

        -sauoq
        "My two cents aren't worth a dime.";