in reply to Comparing hashes and arrays

If I understand you well this should work:

map{/(\S+)\s+([\d.]*)/;$2?($a{$1}=$2):($a{$1}=999)}<FILE>; map{push(@result,$a{$_})}@order;


Update $anarion=\$anarion;

s==q^QBY_^=,$_^=$[x7,print

Replies are listed 'Best First'.
Re: Re: Comparing hashes and arrays
by Sifmole (Chaplain) on Sep 06, 2001 at 16:38 UTC
    That is probably a pretty good start on a golf answer. I do wonder however whether it was at all useful to a user who asks this level of question. Perhaps you could explain how it works to the inquiring monk, that would make it more valueable.

    Update I don't believe this returns the right result either. I am still checking out why, will update shortly.

    Update 2:
    The solution you presented fails to produce the requested 999 result in the case of the missing entry. It also fails to capture the negative value, -7.9.

    I will break down the provided solution so the questioner can perhaps understand what is going on better.

    map{ # map is a way of building a loop # map returns a list of the resulting values. # this use of map makes no use of the returned list # which is often considered bad form, however when # golfing it can be useful for shortening your code. /(\S+)\s+([\d.]*)/; # this is a regular expression # (\S+) says to grab 1 or more # non-white-space characters, # the result captured to $1 # \s+ says to grab 1 or more # white-space characters # ([\d.]*) says to grab either # digits (\d) or a period (.) # 0 or more times. # this will be captured to $2 $2 # This is a a ternary operator # A sometimes useful way of # writing an if-else statement. # This says "if $2" ? ( $a{$1} = $2 ) # then set $a{$1} to $2 : ( $a{$1} = 999 ) # else set $a{$1} to 999 }<FILE>; # the lines read from <FILE> will be used # as input to the map, as $_ map{push(@result,$a{$_})}@order; # again a map, taking the order array and pushing the # related values from the $a hash into @results # giving you the ordered numbers.
    This code has two errors, and one potential gotcha.
    • ([\d.]*) does not catch the negative test value. It could be rewritten as (-?\d.+). Of course this will also catch values like -75.45.23.35
    • The gotcha,  $2 ? ... will give the wrong result if the value associated with the name is 0 (zero). This can be fixed by using $2 ne '', as one possibility, instead.
    • map{push(@result,$a{$_})}@order; will not return the appropriate '999' responses, because the @order values were never set if the did not appear in the input file. We could fix this with map{push(@result,defined $a{$_} ? $a{$_} ? 999)}@order ( assuming the other fixes are in place.

    The resulting fixed code...

    map{/(\S+)\s+(-?[\d.]+)/;$a{$1}=$2?$2:''}<DATA>; map{push(@result,defined $a{$_} ? $a{$_} : 999)}@order;

    Perhaps we should call golf-on?

      $2 ? ... will give the wrong result [...] This can be fixed using $2 ne ''

      Well, it seems to me from the original post that the file will always have both columns; if the match doesn't succeed then the line is not valid and (maybe?) shouldn't be considered.

      The code becomes (note that map in void context is almost always considerably slower than for):

      # assuming @i = map "name$_" 1..5 /(\S+)\s+(-?\d+(?:.\d+)?)/and$a{$1}=$2 for<DATA>; push@o,exists$a{$_}?$a{$_}:999 for@i;

      Remember, this simply ignores lines in the file that don't have both columns. It also ignores a second decimal (and everything after) in the second column. It all depends on how lenient we want to be of bad data.

      bbfu
      Seasons don't fear The Reaper.
      Nor do the wind, the sun, and the rain.
      We can be like they are.

      Your code has now an error, that mine has not, if the second value is null.
      /(\S+)\s+(-?[\d.]+)/;
      If the second value is null the re doesn't match and $2 is the one of the match before.
      Update:
      Sorry i dont read that bbfu has fixed it adding ?

      $anarion=\$anarion;

      s==q^QBY_^=,$_^=$[x7,print

        Did you actually run it before you told me it was wrong?

        If the second value is null as in something like

        __DATA__ name1 4.5 name3 name5 6.5 name4 -7.9 name6 3.2
        The the entire pattern will not match since the second value is required according to the regex. Also, a simple test of adding a print statement during the match will educate you that the $1 and $2 are not carried over.
        Run this to see...
        my @order = qw(name1 name2 name3 name4 name5 name6); map{/(\S+)\s+(-?[\d.]+)/;$a{$1}=$2?$2:'';print "$1 -- $2 \n";}<DATA>; map{push(@result,defined $a{$_} ? $a{$_} : 999)}@order; print join("\n", @result),"\n"; __DATA__ name1 4.5 name3 name5 6.5 name4 -7.9 name6 3.2
        Notice the added print line will show you that $1 and $2 are empty, not the previous values.

        So, to conclude -- actually running it would have shown you that there was no error.