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

I've gone with hdb's suggestion in the other node with the nested foreach loops but I simplified the hash definition to

$haystack{"$a, $b, $c"} =  \@zeros;

I reversed the hash after reading that in perl, hashes are optimized for searching the keys, so now the \@zeros are the keys. But they're arrays, at least in my head. I'm used to thinking in terms of vectors, sets of ordered pairs, etc & not strings or whatever.

I'm interested in the keys that only contain integers so the "something" I was thinking of using a regex like this

/ (.*\.0000.*)|(.*\.9999.*) /

because that would find floats with the right form. It's just I'm not sure what to put in the grep to make sure I'm getting only @zeros that have ALL integers inside & not just at least one. I wouldn't hve thought to use more than one grep like Don Coyote though. Maybe I need to learn more about grep... & then after finding a slice with the right keys, print out the corresponding values. But it's the grep part that I'm stuck on.

Replies are listed 'Best First'.
Re^3: question about what to grep(?)
by hdb (Monsignor) on Apr 12, 2013 at 15:52 UTC

    I do not think that reversing the hash helps. In any case you should define a function that returns true (ie 1) if the argument is (approximately) an integer and then do a grep on the \@zeroes.

    # untested sub is_approximately_an_integer { my $x = shift; my $eps = 0.0001; return abs( $x-round($x) ) < $eps; }

      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;

        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} );