qodeninja
qodeninja

Reputation: 11266

How can I quickly filter a hash given an array of keys?

This is an over-engineered solution for something I think can be done better. Basically it takes an array of keys to create a filter string, which is checked against every key in the hash to see if that key has an index in the filter string... The exclude flag flips the logic to include or exclude based on the result of _filter. Probably not the best way. Any better ways?

  sub _filter{
    my ($filter,$key,$joiner) = @_;
    $joiner = $joiner ? $joiner : '+';
    my $i = index($filter,$key);
    if($i >= 0){  
      my $c;
      $c = substr($filter, $i-1, 1); 

      print STDERR "\nc => $c [$key][$i]";

      if($i==0){ return 1; }
      return($c eq $joiner);  
    }
    return 0;
  }

  sub hashFilter{
    my($hash,$filter_keys,$exclude) = @_;
    return 0 unless isHash($hash) && $filter_keys;

    $exclude = $exclude ? $exclude : 0;
    my $filter = isArray($filter_keys)? join('+',@$filter_keys) : $filter_keys;
    print STDERR "FILTER is > $filter";

    my $p = {map { ( _filter($filter,$_) == $exclude )  ? ($_ => $$hash{$_}) : () } keys %$hash};

    return $p;
  }

#isArray() and isHash() just check the ref value for "ARRAY" or "HASH" respectively

...using standard perl without additional Modules! =]

Some thoughts here?

Using map, and index... are these fast-ish methods vs doing regex, or are there better functions to use?

Upvotes: 3

Views: 8017

Answers (2)

Zaid
Zaid

Reputation: 37146

Hash slice, anyone? :

my %filtered_hash;
@filtered_keys = grep { exists $hash{$_} } @filtered_keys;
@filtered_hash{@filtered_keys} = @hash{@filtered_keys};

Upvotes: 9

jwodder
jwodder

Reputation: 57520

my %filtered_hash = map { $_ => $hash{$_} } grep { exists $hash{$_} } @filter_keys;

Upvotes: 16

Related Questions