my $new = {}; tree($new, $_, $hash{$_}) for keys %hash; sub tree { my ($target, $key, $val) = @_; my ($char, $rest) = split /\./, $key, 2; unless (defined $rest) { $target->{$char} = $val; return; } $target->{$char} ||= {}; tree($target->{$char}, $rest, $val); }