#!/usr/bin/perl -w # # treemap BLOCK HASHREF # treemap BLOCK ARRAYREF # # Works like map, for arbitrary nested data structures. Data are # are modified in-place (unlike map). Returns the original reference. # Hash keys are not modified. # # UPDATE: now handles scalar references, and trimmed an unnecessary line # as suggested by dkubb (thanks!) # # Handles cyclical references just fine, thank you. # sub treemap (&$) { &_treemap } sub _treemap { my ($code, $node, $refs) = @_; if (not my $type = ref $node) { local $_ = $node; $node = &$code(); } elsif (not exists $refs->{$node}) { undef $refs->{$node}; # sneaky, eh? if ($type eq 'HASH') { $node->{$_} = _treemap($code, $node->{$_}, $refs) for keys %$node; } elsif ($type eq 'ARRAY') { $_ = _treemap($code, $_, $refs) for @$node; } elsif ($type eq 'SCALAR') { $node = \_treemap($code, $$node, $refs); } } $node; } ####################### EXAMPLE ############################# $data = { 'nums' => [ 'one', 'two', 'three', 'four', [ 'five', 'six', [ 'seven', 'eight', ]]], 'two' => '2', 'doh' => \'blah blah', 'more' => { 'a' => 'vala', 'b' => 'valb', 'c' => 'valc', 'd' => 'vald' } }; use Data::Dumper; print Dumper treemap { "-=\U$_=-" } $data; print Dumper treemap { s/\W/./g; $_ } $data; print Dumper treemap { reverse lc } $data;