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

Hello monks, I am trying to toggle an array with 0s and 1s. Ex: @array=(0,1,0) should become @array=(1,0,1)
#!/usr/bin/perl @array=(0,1,0); foreach $i (@array){ print "\n$i\n"; } for($i=0;$i<@array;$i++){ $array[$i]=!$array[$i]; } print "After toggling\n"; foreach (@array){ print "\n$_\n"; }
output: 0 1 0 After toggling 1 1 why doesnt Not(!) toggle a 1 to 0? Am i doing something wrong here? Any better way to toggle the values in an array apart from looping through and changing the values. I know this is an absolute beginner's question..but any help is appreciated. Thanks in advance

Replies are listed 'Best First'.
Re: Logical Not not working!!!
by james2vegas (Chaplain) on Aug 20, 2010 at 19:45 UTC
    Booleans in Perl are not 1s and 0s, they are 0, '0', "", undef as "FALSE", and everything else as "TRUE". So negating "1" (TRUE) gives you "" (FALSE). If you need it to be a number, do something like $false_value += 0 or my $number = $false_value ? 1 : 0
Re: Logical Not not working!!!
by kennethk (Abbot) on Aug 20, 2010 at 19:49 UTC

    Some reading that might make this behavior more clear is Scalar values from perldata.

    In order to have its ability to silently work with strings, numbers and booleans without explicit coding of intent, Perl actually stores appropriate values internally. When you use the expression $var = !$var;, you set the variable to FALSE and clear out any numbers or strings associated with it. When you then ask it to print $var, Perl checks what it knows about the value. Since you want a string and the value is FALSE, it outputs "", the false string. Hence, after toggling, you actually have @array = ('1', '', '1'); You can get your expected behavior if you numify, for example with the code $_ += 0 foreach @array;. This will tell Perl to store a numerical value, which it will check before output.

    As a side note, you should pick visible characters as delimiters when checking what you are actually outputting. If you'd used print "<$_>"; for example, you would have gotten the much more obvious <1><><1> as output.

      Thanks for a very clear explanation and advice about the log..I think its is a profound concept for a beginner..I am glad I asked
Re: Logical Not not working!!!
by ikegami (Patriarch) on Aug 20, 2010 at 20:21 UTC

    Why do you expect zero specifically?

    The false value typically returned by Perl is a special value that's "" when treated as a string and 0 when treated as a number.

    $ perl -wle'my $x = !1; print "".$x; print 0+$x;' 0 $ perl -wle'my $x = ""; print "".$x; print 0+$x;' Argument "" isn't numeric in addition (+) at -e line 1. 0 $ perl -wle'my $x = 0; print "".$x; print 0+$x;' 0 0
      I am using it check the results later in the code..but thanks guys!!
        You apparently have a boolean, so checking involes using
        if (!$value)
        instead of
        if ($value == 0)

        Mind you, the latter would work fine with !1 as well, so I don't see the problem.

        If need to format it to print it, you can use the conditional operator.

        print("value = ", $value?"true":"false", "\n");

        But there's no need to format it until it's time to output it.

Re: Logical Not not working!!!
by JavaFan (Canon) on Aug 20, 2010 at 22:21 UTC
    If you want your results to be numbers, don't apply boolean logic to them. Use numbers. Assuming you know @array is filled with 0 and 1, you could do:
    @array = (0, 1, 0); @array = map {1 - $_} @array; say "@array"; # 1 0 1
    I guess in Perl6, the middle line can be written as @array = 1 >>-<< @array and be considered a vast improvement.
Re: Logical Not not working!!!
by CountZero (Bishop) on Aug 21, 2010 at 07:35 UTC
    Rather than using a C-style for-loop, a more Perlish way of dealing with the array is as follows:
    use strict; use warnings; use Data::Dumper; my @array = (1,0,1); for my $item (@array) { $item = !$item + 0; } print Dumper(\@array);
    $item becomes an alias for each element of @array: so whatever you do to $item you really do that to the actual element of the array.

    Update: or even shorter, but perhaps less legible:

    $_=!$_+0 for @array;

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

Re: Logical Not not working!!!
by locked_user sundialsvc4 (Abbot) on Aug 20, 2010 at 19:45 UTC

    Not sure why you have three outputs on the first line and only two on the second, but nevermind.   Just use $array[$i] = ($array[$i] ? 0 : 1);

    This is the sort of “problem” that just is not worth pulling out hair over.   “Don’t bother to ask Why.   Just write Something That Works, and that is reasonably clear to you and to your successor, and move along.”

      Thats the output..its not printing anything when i try to print !1, but ya..I think the james2vegas's explanation that 1 is negating to " " makes sense...Thanks for replying
Re: Logical Not not working!!!
by BrowserUk (Patriarch) on Aug 21, 2010 at 07:53 UTC

    O => 1; 1 => 0 is the truth table for exclusive disjunction; ie. XOR:

    print @a;; 1 1 0 0 1 1 0 0 0 0 0 1 1 1 0 0 $_ ^= 1 for @a;; print @a;; 0 0 1 1 0 0 1 1 1 1 1 0 0 0 1 1
Re: Logical Not not working!!!
by Generoso (Prior) on Aug 20, 2010 at 22:12 UTC

    This is working for me it does not use Boolean values.

    #!/usr/bin/perl # use strict; use warnings; while (<DATA>) { print; chomp; foreach (split /,/){print $_ ? "0," : "1,";} print "\n"; } __DATA__ 0,1,1 1,1,0 0,1,0 1,0,0 1,1,1
Re: Logical Not not working!!!
by Anonymous Monk on Aug 21, 2010 at 04:17 UTC
    Here's a perlish way to write that snippit
    use strict; use warnings; my @foo = (0, 1, 0); print " \@foo: @foo\n"; $_ = !$_?1:0 for @foo; print "!\@foo: @foo\n";
Re: Logical Not not working!!!
by Ratazong (Monsignor) on Aug 21, 2010 at 10:25 UTC

    Just for completeness: the following node lists a lot of additional ways of toggeling between 0 and 1: Boolean counter?