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


in reply to Warning is right or not ?

The function  get_IATA() defined in the OP returns either a two element list if the condition  $data eq $airline is ever true, or the pre-post-incremented value of  $countfalse otherwise. (BTW: Is the latter behavior really intended?) The effects of assigning a multi-element list in scalar versus list context are shown in the code example below. Is the behavior in the scalar assignment below similar to the unspecified failure mentioned in the OP? If so, the proper cure is to return only a single scalar (perhaps the hash value with a concatenated newline) and assign in scalar context, i.e., to  $hash{'AirIATA'} and not to a slice.

>perl -wMstrict -MData::Dump -le "my %hash; ;; $hash{'AirIATA'} = get_IATA(); dd \%hash; ;; @hash{'AirIATA'} = get_IATA(); dd \%hash; ;; sub get_IATA { return 'useful', 'unexpected'; } " Scalar value @hash{'AirIATA'} better written as $hash{'AirIATA'} at .. +. { AirIATA => "unexpected" } { AirIATA => "useful" }

Replies are listed 'Best First'.
Re^2: Warning is right or not ?
by Anonymous Monk on Dec 21, 2012 at 07:43 UTC

    You are right, but the cause of returning more than single scalar was a typo, so its fixed now.

    (BTW: Is the latter behavior really intended?) Do you mean $count++ ?

    If so, I need the previous value of @data, so if you can tell me a better solution I'll use it.

    Because if I try the code as

    if ( grep( /^$airline/, @data) ) { return $data[-2]; }
    it returns wrong value if there are additional notes in the definition file

      ... I need the previous value of @data ...

      If you mean you need to return the element in the  @data array immediately prior to the first element in the array that matches the string passed into the function, I think I would use something like this (Update: an empty string is returned if no match):

      >perl -wMstrict -le "print get_IATA('bar'); ;; sub get_IATA { my ($airline) = @_; ;; my @data = qw(fee fie foe foo barbell boff); ;; for my $i (1 .. $#data) { return $data[$i - 1] if $data[$i] =~ m{ \A \Q$airline\E }xms; } return ''; } " foo

      Update: Here's a variation that returns every element in the  @data array immediately prior to an element in the array that matches the string passed into the function. An empty list is returned if no match.

      >perl -wMstrict -le "printf qq{'$_' } for get_IATA('bar'); ;; sub get_IATA { my ($airline) = @_; ;; my @data = qw(fee fie yyy barfly foe fum zzz barbell foo); ;; return map { $data[$_] =~ m{ \A \Q$airline\E }xms ? $data[$_ - 1] : () } 1 .. $#data ; } " 'yyy' 'zzz'

        Thank you very much for your tips. With my irregual data I had to change my code( and data) and your tips helped alot.

        In my check table (csv), I have 3 character codes(ICAO) and their equivalent 2 character codes(IATA) and descriptions. At first, IATA was at first column so I needed previous element of the array when the key was found. But after having an example of irregular ICAO code, which has 2 characters that matches its IATA code, the code didn't help since Perl stops after the first matching. And that IATA code is used three times in the table ( 1 ICAO, 2 IATA)

        Then I changed IATA and ICAO columns' order and changed the code with your help and now it works. Though it may be clumsy, i think its pretty clear.

        --$hash{'AirIATA'}= get_IATA($airlineLoc,$hash{'Airline'}) ; ------------------------------------------------------- sub get_IATA { my $file = shift; my $airline = shift; my @data; open(my $fh, '<', $file) or die "Can't read file '$file' [$!]\ +n"; while (my $line = <$fh>) { my @fields = split(/;/, $line); push @data, @fields; } close($fh); my @results= map { $data[$_] =~ m{ \A \Q$airline\E }xms ? $data[$ +_ + 1] : () } 1 .. $#data; if ($#results>1) { return $results[1]; } elsif ($#results>0) # Do I need a second check, like <2 ? { return $results[0]; } else { print "Airline $airline has no definition in $file fil +e\n"; exit; # Program should stop if there is no match } }