http://qs321.pair.com?node_id=385879

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

Somebody asked me a question about comparing arrays with == and comparing array slices with ==. It's not as straightforward as you might think. So what is an array slice anyway?
#!/usr/bin/perl use strict; use warnings; use Data::Dumper; my @x = (2,3); my @y = (7,8); my @z = (9,8,7,6,5,4,3,2,1); # probably everybody would agree that @x == @y, because they have # the same number of elements if (@x == @y) { print "x == y\n"; } if (@x == @z) { print "x == z\n"; } if (@y == @z) { print "y == z\n"; } # But how about slices? They have the same number of elements, # right? if (@x[0,1] == @y[0,1]) { print "x slice == y slice\n"; } if (@x[0,1] == @z[0,1]) { print "x slice == z slice\n"; } if (@y[0,1] == @z[0,1]) { print "y slice == z slice\n"; } print "x array is: ", Dumper(@x), "\n"; print "y array is: ", Dumper(@y), "\n"; print "z array is: ", Dumper(@z), "\n"; print "x slice is: ", Dumper(@x[0,1]), "\n"; print "y slice is: ", Dumper(@y[0,1]), "\n"; print "z slice is: ", Dumper(@z[0,1]), "\n"; print "scalar x slice is: ", scalar(@x[0,1]), "\n"; print "scalar y slice is: ", scalar(@y[0,1]), "\n"; print "scalar z slice is: ", scalar(@z[0,1]), "\n"; # try assigning my @q = @x[0,1]; my @r = @y[0,1]; if (@q == @r) { print "q == r\n"; } # okay how about this? if (@q == @x[0,1]) { print "q == x slice\n"; } __END__

Replies are listed 'Best First'.
Re: So what is an array slice anyway?
by blokhead (Monsignor) on Aug 26, 2004 at 01:38 UTC
    First, make sure you realize that lists and arrays are different things; they return different things in scalar context. A list returns its last element, while an array returns its size.
    #!/usr/bin/perl -l ## list: print scalar (4,5,6,7); ## 7 ## array: my @foo = (4,5,6,7); print scalar @foo; ## 4
    Next, understand that an array (or hash) slice is simply a list (see here for one discussion). In other words, writing @foo[1,2] is like writing ($foo[1], $foo[2]) explicitly. Yes, it's a bit confusing because the @ sigil is reminiscent of an array...

    Now you can see why the array slices didn't compare with == like you thought. The == operator imposes scalar context, which causes the slices to return their last element and the arrays to return their size. If it helps, scatter some print scalar @foo[0,1] statements around to see what numbers really are being compared with == in those conditionals.

    blokhead

      lists and arrays ... return different things in scalar context.

      Actually, there is no such thing as a list in scalar context. What you describe is the behavior of the comma operator in scalar context. There never is a list.

      Update: this is explained in perldoc -q "between a list". Incidentally, it is nearly exactly the same as what I said -- I must have subconsciously memorized the FAQ entry. :-)

      It might be interesting to note that you can see this in action with B::Deparse, e.g.:

      $ perl -MO=Deparse -e 'print scalar (2, 5, 7, 9);' print scalar('???', '???', '???', 9); -e syntax OK
      I know that lists and arrays are different, but as yet I haven't found in the documentation what the difference is. Where in the documentation is the difference between lists and arrays explained? I found this in perldata:
      If you evaluate an array in scalar context, it returns the length of the array. (Note that this is not true of lists, which return the last value, like the C comma operator, nor of built-in functions, which return whatever they feel like returning.)

      There is also a section on slices in perldata, but where does it say that a slice is a list?

        where does it say that a slice is a list?

        In a few places spread throughout perldata. Interestingly, the most direct statement on the subject is not from the section on Slices, but is a parenthetical remark in the section on Context:

        Assignment to a list (or slice, which is just a list anyway) also evaluates the righthand side in list context.

Re: So what is an array slice anyway?
by antirice (Priest) on Aug 26, 2004 at 03:25 UTC

    Behold!

    my @p = (0..10); my @q = (1..9); if ( ( () = @p[0,1,2] ) == ( () = @q[3,6,1] ) ) { print "p slice == q slice\n" }

    You can either assign your slice directly to an array and compare the scalar value of the arrays or you can use ( () = LIST ) and compare them directly.

    Disclaimer: I also like Lisp, so I see some beauty in the parentheses bomb.

    antirice    
    The first rule of Perl club is - use Perl
    The
    ith rule of Perl club is - follow rule i - 1 for i > 1

      That's an interesting thing to be doing. However, I think the person who asked me the question is actually trying to find out whether arrays and array slices are "equal" by using the "==" operator. I tried to explain how it was comparing the number of elements in arrays by using scalar context, but he suddenly went to bed. I was hoping there would be a function in List::Util to compare arrays and return if they are equal, but no luck there. Sorry for not making that clear before. What he wants to do is to 1) compare arrays to see if they have all the same elements in, and 2) compare array slices to see if they have all the same elements in. I think he should just write a subroutine to do it. But I sure think he shouldn't be using "==" to do it.

        Here's an idiomatic way to test whether the contents of two arrays are equal — assuming the elements are numbers, anyway.

        print "equal\n" if @array1 == @array2 and !grep $array1[ $_ ] != $array2[ $_ ], 0 .. $#array1;

        In scalar context, grep evaluates to the number of elements it returned, so that condition says "if both arrays have the same length, and if no elements are found which are not equal".

        Makeshifts last the longest.

        Okay, here's what I'm going to give him. Hopefully it will make him think again about using == for this sort of thing. Hopefully it has enough examples and pointers to the documentation to show him what's up.

        Thanks for your help.

        I do this sort of thing a lot. List::Compare makes it pretty easy.