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

Pretty simple question this. I'm sure there is a way to do it but I can't seem to figure it out. This question is just about efficiently written code.

Basically I want to return just one element of an array where the array is actually a return value from a function without having to define a temporary variable.

For example using localtime I might just want to return the hour which could be done using.

my @temp=localtime(time); print $temp[ 2 ]

I've tried different types of syntax but can';t quite seem to figure out the best way, I was hoping something like :

print localtime(time)[ 2 ]

would work. Another example might be the return value from a Win32::ODBC Error call.

print $db->Error[ 1 ]

Which again of course doesn't work!

Could any monks offer insight or give example as to how I would do this.

Replies are listed 'Best First'.
Re: array element return syntax
by ikegami (Patriarch) on Mar 29, 2006 at 15:32 UTC

    Close. You need parens around the list expression being indexed.

    $hour = (localtime(time))[ 2 ];
    You can also extract multiple elements:
    my ($y, $m, $d) = (localtime(time))[ 5, 4, 3 ];

    This feature is called a "list slice", and it's documented in perldata.

      H:\scripts>perl -e "print (localtime(time))[2]" syntax error at -e line 1, near ")[" Execution of -e aborted due to compilation errors.
      8(

        -w will help you understand what's going on.

        $ perl -we "print (localtime(time))[2]" print (...) interpreted as function at -e line 1. syntax error at -e line 1, near ")[" Execution of -e aborted due to compilation errors.

        use diagnostics is even better.

        $ perl -Mdiagnostics -we "print (localtime(time))[2]" print (...) interpreted as function at -e line 1 (#1) (W syntax) You've run afoul of the rule that says that any list op +erator followed by parentheses turns into a function, with all the list operators arguments found inside the parentheses. See perlop/Terms and List Operators (Leftward).

        So stop the parentheses looking like a function.

        $ perl -e "print +(localtime(time))[2]" 16
        --
        <http://dave.org.uk>

        "The first rule of Perl club is you do not talk about Perl club."
        -- Chip Salzenberg

        print is claiming your parens. In other words, Perl sees your code as
        print( ... )[2];
        To fix the problem, use
        print( (localtime(time))[2] );
        or
        print +(localtime(time))[2];

Re: array element return syntax
by Rice (Acolyte) on Mar 29, 2006 at 15:40 UTC
    Subscripts do operate on lists, as you guessed. print also takes a list as its argument, so you need to delimit your lists with parentheses. Try:
    print ( (localtime(time))[2] ) ; print ( ($db->Error)[ 1 ] ) ;
    or even
    print ( (localtime)[2] ) ;
Re: array element return syntax
by kwaping (Priest) on Mar 29, 2006 at 15:42 UTC
    This also works. Update: Not the ideal solution, but at the very least a TIMTOWTDI example.
    print [localtime(time)]->[5];

    You can also use parentheses, as posted previously. However, when dealing with print, for example, you need to let the compiler know that your parens are for wrapping the function and not part of the print statement. This will work for that:
    print +(localtime(time))[5];

    ---
    It's all fine and dandy until someone has to look at the code.
      This also works.
      For some meaning of "works", in the same sense that you can add "sleep 1" in various places in your program and it still "works", albeit slower.

      There's no point in constructing an entire full-fledged array, then take a reference to it, then dereference that reference to get a particular element, then garbage collect the full array, just to get one element of it. It's a lot of extra work.

      -- Randal L. Schwartz, Perl hacker
      Be sure to read my standard disclaimer if this is a reply.

        Thanks! That makes sense. It was just the first thing that sprang to my mind, but now I know better.

        ---
        It's all fine and dandy until someone has to look at the code.
      And the slice "equivalent" would be
      my ($y, $m, $d) = @{[localtime(time)]}[ 5, 4, 3 ];

      These construct an array, which makes them slower.

      H:\scripts\7d>perl -e "print ((localtime(time))[2])" 16
      =D Excellent thankyou. Could I be cheeky and ask just how print ((localtime(time))[2]) works at each step as regards each context

      From :

      time

      To :

      print ((localtime(time))[2])?

        1. time returns a number that represents the number of seconds since the start of the epoch.
        2. localtime(time) returns a list of values that represent the seconds, minutes, etc. in the local time zone
        3. (localtime(time))[2] indexes into the list (a convenience that perl allows) and returns the 3rd item in the list
        4. print((localtime(time))[2]) outputs the 3rd item in the list returned by localtime

        The only "weird" part might be why there are extra parens on the print. I.e., why not

        print (localtime(time))[2];
        And the answer is precedence. To perl, that looks like a function call (to the print function) with a parameter of localtime(time). So it's really
        print(...)[2];
        Which doesn't make any sense, so perl tells you so.