%patterns = ( 5 => { undef => { 8 => ['p1'], 4 => ['p2'] } }, undef => { 4 => { 1 => ['p3'] }, 3 => { 5 => ['p4'] } } ); #### my @row = the data, without the record_id!; my @matching = (\%patterns); while (@row and @matching) { my $value = shift(@row); my @next_matching; foreach my $branch (@matching) { if (exists $branch->{$value}) { # there is a matching pattern if (ref($branch->{$value}) eq 'HASH') { # the pattern requires some more values to match push @next_matching, $branch->{$value}; } else { # the pattern matched completely push @found_patterns, @{$branch->{$value}}; } } if (exists $branch->{undef()}) { # there is a patter that doesn't care about this value if (ref($branch->{undef()}) eq 'HASH') { # the pattern requires some more values to match push @next_matching, $branch->{undef()}; } else { # the pattern matched completely push @found_patterns, @{$branch->{undef()}}; } } } @matching = @next_matching; } # and now all the matching patterns are in @found_patterns # the code is untested and only intended as an example