http://www.perlmonks.org?node_id=1010790

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

Hi! Monks,
Why does the first code work, but not the second one? Can you help me understand. Thank you!

#!/usr/bin/perl use warnings; use strict; use 5.010; my @array = qw(x a m a x); my @reversed = reverse @array; if (@array eq @reversed){ say "this's a palindrome."; } else { say "this's not a palindrome"; }
#!/usr/bin/perl use warnings; use strict; use 5.010; my @array = qw(x a m a x); if (@array eq (reverse @array)){ say "this's a palindrome."; } else { say "this's not a palindrome."; }

Replies are listed 'Best First'.
Re: Palindrome array
by LanX (Saint) on Dec 29, 2012 at 06:13 UTC
    The ugly truth is both don't work!

    eq forces scalar context and is meant to compare strings

    So in the first code you are checking if the sizes (after stringification) are equal.

    DB<107> @a = 1..3 => (1, 2, 3) DB<108> @a eq "3" => 1

    in the second you have scalar from reverse on RHS

    DB<123> (reverse @a) => (3, 2, 1) DB<124> scalar (reverse @a) => 321 DB<125> "321" eq (reverse @a) => 1

    please stop doing weird things!

    you can try the (less weird) smart match operator ~~ to compare arrays.

    DB<129> @a=(3,1,3) => (3, 1, 3) DB<130> @a ~~ [reverse @a] => 1 DB<131> @a ~~ [3,1,3] => 1 DB<132> @a=1..3 => (1, 2, 3) DB<133> @a ~~ [reverse @a] => ""

    a poor man's solution with eq is to explicitly stringify on both sides.

    DB<143> @a=(3,1,3) => (3, 1, 3) DB<144> @ar=reverse @a => (3, 1, 3) DB<145> "@a" => "3 1 3" DB<146> "@a" eq "@ar" => 1

    But this depends on the nature of your array elements, don't be too surprised about:

    DB<151> "@a" => "3 1 3" DB<152> @b=(3,"1 3") => (3, "1 3") DB<153> "@a" eq "@b" => 1

    Cheers Rolf

Re: Palindrome array
by Athanasius (Archbishop) on Dec 29, 2012 at 06:04 UTC

    The string comparison operator eq puts its operands into scalar context:

    #! perl use warnings; use strict; use 5.010; say 'equal' if context('1') eq context('2'); sub context { my $c = (defined wantarray) ? (wantarray ? 'list' : 'scalar') : 'void'; say '(', shift, '): is in ', $c, ' context'; return 42; }

    Output:

    15:56 >perl 457_SoPW.pl (1): is in scalar context (2): is in scalar context equal 15:56 >

    So, neither code snippet is doing what you want. The first compares the sizes of the two arrays. The second compares the size of @array with the value returned by reverse, which

    In scalar context, concatenates the elements of LIST and returns a string value with all characters in the opposite order.

    To compare the contents of the two arrays, use the smart match operator ~~. See How do I test whether two arrays or hashes are equal?

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Re: Palindrome array
by davido (Cardinal) on Dec 29, 2012 at 09:47 UTC

    There are a number of good ways to approach this. Here's one way that uses a CPAN module:

    use String::Palindrome qw( is_palindrome ); my @array = qw( x a m a x ); print "@array ", is_palindrome( @array ) ? "is" : "isn't ", "palindromic.\n";

    The above solution works just as well if you pass it a string rather than an array, but in either case it does the job.


    Dave

Re: Palindrome array
by Jim (Curate) on Dec 29, 2012 at 09:01 UTC

    This isn't C. In Perl, a palindrome is properly represented as a string, not an array of characters.

    #!perl use strict; use warnings; my $string = "A Man, A Plan, A Canal -- Panama!"; my $letters = lc $string; $letters =~ s/\W//g; printf qq/"%s" %s a palindrome.\n/, $string, $letters eq reverse($letters) ? "is" : "isn't"; __END__ "A Man, A Plan, A Canal -- Panama!" is a palindrome.

    If this is a homework assignment, tell your teacher you expect to be given more verisimilar programming problems. ;-)

    If you're writing a Perl program to identify palindromic sequences in nucleic acids, you should still use strings, not arrays of characters, in my opinion.

    Jim

Re: Palindrome array
by karlgoethebier (Abbot) on Dec 29, 2012 at 19:35 UTC

    BTW, why array? I just cheated this from Re^2: palindrome using regular expressions...

    #!/usr/bin/perl + use strict; use warnings; my $palindrome = 'lagerregal'; my $check = reverse $palindrome; print "yes\n" if $check eq $palindrome; $palindrome='xamax'; $check = reverse $palindrome; print "still yes\n" if $check eq $palindrome; __END__

    Regards, Karl

    «The Crux of the Biscuit is the Apostrophe»

Re: Palindrome array
by 2teez (Vicar) on Dec 29, 2012 at 05:52 UTC

    "...Why does the first code work, but not the second one? Can you help me understand..."

    using this

    if (@array eq (reverse scalar @array)){..
    gives the result you want on the second one.
    Does that help or solve the puzzle by any means?

    If you tell me, I'll forget.
    If you show me, I'll remember.
    if you involve me, I'll understand.
    --- Author unknown to me
      > if (@array eq (reverse scalar @array)){..

      Sorry I can't let this stand uncorrected!

      DB<108> @array=1..9 => (1, 2, 3, 4, 5, 6, 7, 8, 9) DB<109> @array eq (reverse scalar @array) => 1 DB<110> @array=0..9 => (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) DB<111> @array eq (reverse scalar @array) => "" DB<112> scalar (reverse scalar @array) => "01" DB<113> scalar @array => 10

      Cheers Rolf

        Hi LanX,

        > if (@array eq (reverse scalar @array)){..
        "..Sorry I can't let this stand uncorrected!.."
        There is really no need to be sorry, because your assertions and "tests" are so correct and right I.

        However, I believe Athanasius first caught the message I was trying to pass to the OP, in this line
        ..The string comparison operator eq puts its operands into scalar context..

        ++ LanX

        I -> Updated.

        If you tell me, I'll forget.
        If you show me, I'll remember.
        if you involve me, I'll understand.
        --- Author unknown to me