Mr.T has asked for the wisdom of the Perl Monks concerning the following question:

Hello,
Coming from a *cough*Pascal background, with sprinkles of C, and Java, I was wondering if there was a different way to exchange one variable to another without having to use variables that are temporary, such as an example like this (which could eventually be used to sort information, or some such:)

$temporary = $first; $first = $second; $second = $temporary;


Is there a way that I can make $first exchanged with $third, without having to use the extra (wasteful) variable $next?

I have heard from a friend that there is a way to do this, but didn't tell me.

Mr.T
qw/"I pity da foo' who don't use Perl!"/;

Replies are listed 'Best First'.
Re: Exchanging Variables
by suaveant (Parson) on Aug 10, 2001 at 00:19 UTC
    Yes! you can do...
    ($first,$second) = ($second,$first);

                    - Ant
                    - Some of my best work - Fish Dinner

      No way! You are saying that all I have to do is:
      ($first,$second) = ($second,$first);

      and it automatically exchanges them for you?

      Is there any other ways of doing this that might be used for other tasks? Or is this the only *reasonable* way to do it?

      Mr.T
      qw/"I pity da foo' who don't use Perl!"/;
        Asigning an array to a list of variables is a common way to give meaning full names to the items in an array. You can use it to make handling the returns of functions like local time easyer.
        IE:
        ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); as opposed to
        @time = localtime(time); and having to remeber that $time[2] is the hour.

        If you have an array in the list on the left side of the = it will gobble up all the remaing items in the array on the right side. You need to be careful of this, because anything following the array will not have anything asigned to it.
        IE:
        ($one, $two, @three, $four) = ('one', 'two', 'three', 'four'); $one will equal 'one'
        $two will equal 'two'
        @three will equal ('three', 'four')
        and $four will be undefined

        There are many ways to use this feature of perl.
        You will probably see
        sub do_stuff { my ($foo, $bar) = @_; }
        to get the arguments sent to a subroutine into named variables often.

        This is otherwise known as DWIM, Do What I Mean.

        Cool aint it?

        Basically, whenever you assign to a list, each element gets assigned to, all in parallel. So, in parallel, the value of the first gets assigned to the second, and the value of the second (which isn't *yet* the previous value of the first) gets assigned to the first; thus, they get exchanged. See?
        re: Is there any other ways of doing this that might be used for other tasks? Or is this the only *reasonable* way to do it?

        You might want to ask that in the Obfuscation section and then stand back.

        how about:

        push @INC, $first, $second; # not a temporary since it already exists! $_= pop @INC foreach ($first, $second);
        You can do that... I believe it has something to do with perl creating a temporary anonymous array... but I am not entirely sure...

                        - Ant
                        - Some of my best work - Fish Dinner

Re: Exchanging Variables
by dailylemma (Scribe) on Aug 10, 2001 at 01:34 UTC
    One way to swap two variables with no temporaries that isn't specific to perl is:

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


    Update: The '^' operator is called "exclusive or" or XOR. It returns the bitwise XOR of the operands. XOR is equivalent to bitwise addition mod 2.
      First of all $a and $b are special in Perl so it is a good idea to avoid using them, even for throw-away variables.

      That aside, this method of swapping data is unreliable. Witness:

      my $x = ["hello"]; my $y = ["world"]; print "We have \$x=$x and \$y=$y.\n"; print "The first element of \$x is '$x->[0]'\n"; print "The first element of \$y is '$y->[0]'\n"; print "Now swapping...\n"; $x = $x ^ $y; $y = $x ^ $y; $x = $x ^ $y; print "We have \$x=$x and \$y=$y.\n"; print "The first element of \$x is '$x->[0]'\n"; print "The first element of \$y is '$y->[0]'\n";
      What happened, of course, is that you stringified the object and so lost the reference.

      Now if you want a sneaky way to swap variables, the following takes a list of variables as arguments and rotates them. The first goes to the end, the rest move forward one. With 2 variables this just swaps.

      my $x = ["hello"]; my $y = ["world"]; print "We have \$x=$x and \$y=$y.\n"; print "The first element of \$x is '$x->[0]'\n"; print "The first element of \$y is '$y->[0]'\n"; print "Now swapping...\n"; rotate($x, $y); print "We have \$x=$x and \$y=$y.\n"; print "The first element of \$x is '$x->[0]'\n"; print "The first element of \$y is '$y->[0]'\n"; # And here is the magic bit sub rotate { @_[0..$#_] = @_[1..$#_, 0]; } # BTW here is something that won't work. Lists are not arrays! :-) sub wont_rotate { @_ = @_[1..$#_, 0]; }
      I think I understand, but I am not exactly sure what the '^' operator does. Please forgive my ignorance, but what does it do, and what is it called? (In Perl.)

      Mr.T
      qw/"I pity da foo' who don't use Perl!"/;
Re: Exchanging Variables
by Hofmator (Curate) on Aug 10, 2001 at 13:21 UTC

    It should be clear by now, but for completeness sake I add

    ($one, $two, $three, $four) = ($three, $one, $four, $two); # and array slicing my @arr = qw/one two three four/; @arr = @arr[2,0,3,1];
    This shows that the whole construct works also for more than one element.

    -- Hofmator

Re: Exchanging Variables
by robsv (Curate) on Aug 10, 2001 at 02:00 UTC
    I also used to code in Pascal (never mind how long ago). If I was swapping two numerics, I used the XOR function. Here's the Perl version (since we ain't Pascal Monks):
    $a = 598; $b = 77; $a = $a ^ $b; $b = $a ^ $b; $a = $a ^ $b; print "$a $b\n";
    Use the ($a,$b) = ($b,$a) version, though. I just put this up for fun: TMTOWTDI!

    - robsv

    Update: Aaargh! Ignore me. dailylemma posted this already. That's what I get for starting a reply, going for a soda, then finishing the reply.
Re: Exchanging Variables
by Anonymous Monk on Aug 10, 2001 at 04:14 UTC
    ( $first, $second ) = ( second, $first );
Re: Exchanging Variables
by Anonymous Monk on Aug 10, 2001 at 10:23 UTC
    ($first, $second) = ($second, $first) will do what you need
Re: Exchanging Variables
by Anonymous Monk on Aug 10, 2001 at 21:33 UTC
    You could always use $_ as the temporary if you're concerned about taking space.