in reply to Re^3: question about what to grep(?)
in thread question about what to grep(?)

I got an uninitialized variable error the way you had it so I added the foreach bit here, & also changed the round to int(). I got your idea:

sub is_approximately_an_integer { foreach my $x ( @zeros ) { $x = shift; my $eps = 0.0001; return abs( $x-int($x) ) < $eps; } }

It seems to work ok like that. I guess next is to use the subroutine with $_ inside grep somehow?

my @wants = grep {  } values %haystack;

Replies are listed 'Best First'.
Re^5: question about what to grep(?)
by hdb (Monsignor) on Apr 13, 2013 at 08:30 UTC

    As always, there is more than one way to do it. Please see code below for some illustrations. Some comments:

    • Using @zeros in the sub is a bad idea. All numbers to be tested should be passed as arguments, see below. I had not mentioned this.
    • "int" only cuts of digits. So int(2.9999) is 2 which is not what you want. One can use it for rounding, but it is more complex and there is a module doing it for us: Math::Round.
    • I have illustrated the use of our test function with a few examples below.
    • In grep you can iterate either over your keys or over the arrays, you just need to call the test function appropriately.
    • As you are iterating over all elements of the hash, speed of lookup is not an issue in my opinion.
    Hope this helps.

    use strict; use warnings; use Math::Round qw/round/; use Data::Dumper; # function returns 1 if all arguments are integer # zero otherwise sub is_approximately_an_integer { my $eps = 0.0001; while( my $x = shift ) { # need to use "round", "int" does not work! return 0 if abs( $x-round($x) ) > $eps; } return 1 } # some test cases print "Testing...\n"; print is_approximately_an_integer( 1, 3.99999999, 5 ), "\n"; print is_approximately_an_integer( 1.2, 3.99999999, 5 ), "\n"; print is_approximately_an_integer( 1, 3.99999999, 5.0000001 ), "\n"; print is_approximately_an_integer( 1, 3.99999999, -5 ), "\n"; print is_approximately_an_integer( 1, 3.99999999, -5.1 ), "\n"; print is_approximately_an_integer( 1, 3.99999999, -5.000000001 ), "\n" +; print is_approximately_an_integer( 1, -3.99999999, -5.000000001 ), "\n +"; print is_approximately_an_integer( 1 ), "\n"; print is_approximately_an_integer( 1.5 ), "\n"; # what if we have hash of arrays ? my %hash = ( "1,2,3" => [ 1, 3.99999999, 5 ], "1,2,4" => [ 1.2, 3.99999999, 5 ], "1,2,5" => [ 1, 3.99999999, 5.0000001 ], # etc ); # this returns only the arrays but lose keys print "\nSelected arrays\n"; my @wants = grep { is_approximately_an_integer( @$_ ) } values %hash; print Dumper( @wants ); # this returns the keys print "\nSelected keys...\n"; my @wants = grep { is_approximately_an_integer( @{$hash{$_}} ) } keys +%hash; print Dumper( @wants ); print "...and the associated array.\n"; # and you can get the arrays as well print Dumper( @hash{@wants} );