sub order_of_sorted { my ( @num, @suff ); for( @_ ) { m/ \A (\d+) \. (.*) /x or die "malformed data"; push @num, $1; push @suff, $2; } sort { $num[$a] <=> $num[$b] or $suff[$a] cmp $suff[$b] } 0 .. $#_; } for my $outer ( ( values %hash )[ order_of_sorted keys %hash ] ) { for my $inner ( ( values %$outer )[ order_of_sorted keys %$outer ] ) { # ... } } #### for my $inner ( ( values %$outer )[ order_of_sorted keys %$inner ] ) { # ^^^^^^^ Correct. ^^^^^^^ Oops.