Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

seeking different ways to slice a 2-d array

by belden (Friar)
on Apr 25, 2002 at 02:13 UTC ( #161836=perlquestion: print w/ replies, xml ) Need Help??
belden has asked for the wisdom of the Perl Monks concerning the following question:

I've got an object method which digs into a hash of arrays of arrays and pulls out the last element of each stored array. Here's my code:
sub whatever { my $self = shift; # ... do stuff to set ar_data... # Slice out the last element of each stored array into a new array my @last_elements; push @last_elements, $_->[$#_] for @{$ar_data}; return \@last_elements; }
After grabbing some water, I walked back and realized that @last_elements is (uh-oh) a transitory variable. (and wouldn'tcha know it, I try to look up on the web why transitory variables are bad, and I can't find anything. Dang; I'm sure dominus wrote about this somewhere. Or maybe this is hard water I'm drinking.) So, with a vague idea that some variables are "good" and others are "bad", I wanted to re-write my method to just return the list of @last_elements without actually storing into a list. (Sidenote: or is this foolish? Am I just inviting bogarts into my code?)

After a bit of toying, I realized that there are other ways to iterate over a list than by using for. Enter sort, map, and grep.


#!/usr/bin/perl use strict; use warnings; # fill the 2-d array my @data; for ( 0..2 ) { push @data, [qw 'a bc def' ]; } # try extracting last element from each stored array my @for_data = slice_with_for ( @data ); my @map_data = slice_with_map ( @data ); my @sort_data = slice_with_sort ( @data ); my @grep_data = slice_with_grep ( @data ); # show the y-axis slices print "for : @for_data\n"; print "map : @map_data\n"; print "sort: @sort_data\n"; print "grep: @grep_data\n"; exit; sub slice_with_for { my @slice_me = @_; my @last_fields; push @last_fields, $_->[2] for @slice_me; @last_fields; } sub slice_with_map { my @slice_me = @_; return map { $_->[2] ? $_->[2] : () } @slice_me; } sub slice_with_sort { my @slice_me = @_; sort { $a->[2] cmp $b->[2] } @slice_me; } sub slice_with_grep { my @slice_me = @data; grep { $_->[2] } @slice_me; } exit;
Prints:
for : def def def
map : def def def
sort: ARRAY(0x80fad5c) ARRAY(0x810c844) ARRAY(0x810c7c0)
grep: ARRAY(0x80fad5c) ARRAY(0x810c844) ARRAY(0x810c7c0)

My questions:
1. What other ways are there to iterate over the list besides for, sort, map, and grep?
2. Why don't my slice_with_grep and slice_with_sort functions return what I'm expecting?
3. Am I drunk, or is the water? That is, have I invented this whole notion of a "transitory variable", or is it really something that exists (albeit momentarily) and should be avoided?

blyman
setenv EXINIT 'set noai ts=2'

Comment on seeking different ways to slice a 2-d array
Select or Download Code
Re: seeking different ways to slice a 2-d array
by Fletch (Chancellor) on Apr 25, 2002 at 02:18 UTC

    ITYM `lexically scoped variable', not transitory. And you're probably thinking of mjd's Coping with Scoping.

      I'd like to read that again when it's updated to describe 'our'. I use 'our' all the time but the cross-over between the previously totally unrelated realms of lexical and package variables is still a bit vague in my mind.

      -sam

        I am very curious to know why you use our so much. I have never had a reason to use it myself because i tend to use OO a lot.

        I recently had a big revelation at (jeffa) 3Re: Whether to use local(), hopefully this post will remove the vagueness from your mind as well.

        UPDATE:
        Oh $#!^ - you are Sam Tregar. Scratch that last sentance! :O

        jeffa

        L-LL-L--L-LL-L--L-LL-L--
        -R--R-RR-R--R-RR-R--R-RR
        B--B--B--B--B--B--B--B--
        H---H---H---H---H---H---
        (the triplet paradiddle with high-hat)
        
      As I learn more about Perl and programming in general, I find myself re-reading articles and saying, "Ohhh.... so that's what it means...". Case in point: Coping with Scoping. Thanks for the pointer.

      Dropping off to sleep last night I realized that the article I was thinking of was a Red Flags article on perl.com. The actual term mjd used was synthetic variables although in a different Red Flags article he talks about synthetic code

      blyman
      setenv EXINIT 'set noai ts=2'

Re: seeking different ways to slice a 2-d array
by stephen (Priest) on Apr 25, 2002 at 03:34 UTC

    A transitory variable is a variable that isn't used for anything other than to schlep data from one line to another. (I'm not sure the term is right, but I think it's what you mean. I call 'em "useless variables", myself.) In other words, if I'm going to say:

    my $foo = get_foo(); do_something($foo);
    Then $foo is a transitory variable. It would be just as simple, and less error-prone, to say:
    do_something( get_foo() );

    Why? Because variables can and should vary. It doesn't seem like such a big deal when the assignment and the use of the variable are right next to each other, but what if they get separated?

    my $foo = get_foo(); if ($snargle = 3 && $foo = 2) { whatever($snargle, $foo); # lots of other stuff here... } do_something($foo);

    Oops, on line 2 up there we changed the value of $foo. Also, it makes refactoring harder-- what if you wanted to pull out the stuff inside the if statement into its own subroutine? It'd be simpler if you didn't have $foo there at all, and just called get_foo() when you needed a foo-value.

    In your code, @for_data, @map_data, @sort_data, and @grep_data are all transitory variables. Ironically, @last_elements is not... you're using it to collect elements! Nothing wrong with that.

    As for why slce_with_sort() and slice_with_grep() aren't doing what you expect, it's because sort and grep don't do what you apparently think they do. :) The block argument to grep is a test block, not a filter block. So the statement

    grep { $_->[2] } @slice_me;
    means, "If the item at index 2 of @$_ evaluates to true, return $_." The last bit is important-- it doesn't return the item at index 2, it returns the whole thing. A similar thing is happening with sort. You're sorting each row based on the value of the last column, and returning a list of the rows. Since the values are identical, it doesn't even change their order. :)

    So where did you get that water? Sounds like powerful stuff. :)

    stephen

(jeffa) Re: seeking different ways to slice a 2-d array
by jeffa (Chancellor) on Apr 25, 2002 at 14:19 UTC
    I always found splice to be a good way to slice an array. Here is an example that you can play with. I am assuming that you always want the last element from each inner array.
    use strict; use Data::Dumper; my @arry = ( [qw(one two three)], [qw(foo bar baz)], ); my @new; push @new, splice(@$_,$#$_,1) for @arry; print Dumper \@new;
    The third argument of '1' for splice is not necessary in this case, but i recommend keeping it in case you decide to remove only one element from any other position. ;)

    Hope this works for you.

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    
      I am assuming that you always want the last element from each inner array.
      Correct!

      Here is an example that you can play with....Hope this works for you.
      Yes, it does - thanks for the new technique

      blyman
      setenv EXINIT 'set noai ts=2'

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://161836]
Approved by VSarkiss
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others examining the Monastery: (8)
As of 2015-07-06 08:43 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The top three priorities of my open tasks are (in descending order of likelihood to be worked on) ...









    Results (70 votes), past polls