1Data::Rmap(3)         User Contributed Perl Documentation        Data::Rmap(3)
2
3
4

NAME

6       Data::Rmap - recursive map, apply a block to a data structure
7

SYNOPSIS

9        $ perl -MData::Rmap -e 'print rmap { $_ } 1, [2,3], \\4, "\n"'
10        1234
11
12        $ perl -MData::Rmap=:all
13        rmap_all { print (ref($_) || "?") ,"\n" } \@array, \%hash, \*glob;
14
15        # OUTPUT (Note: a GLOB always has a SCALAR, hence the last two items)
16        # ARRAY
17        # HASH
18        # GLOB
19        # SCALAR
20        # ?
21
22
23        # Upper-case your leaves in-place
24        $array = [ "a", "b", "c" ];
25        $hash  = { key => "a value" };
26        rmap { $_ = uc $_; } $array, $hash;
27
28        use Data::Dumper; $Data::Dumper::Terse=1; $Data::Dumper::Indent=0;
29        print Dumper($array), " ", Dumper($hash), "\n";
30
31        # OUTPUT
32        # ['A','B','C'] {'key' => 'A VALUE'}
33
34
35        # Simple array dumper.
36        # Uses $self->recurse method to alter traversal order
37        ($dump) = rmap_to {
38
39           return "'$_'" unless ref($_); # scalars are quoted and returned
40
41           my $self = shift;
42           # use $self->recurse to grab results and wrap them
43           return '[ ' . join(', ', $self->recurse() ) . ' ]';
44
45         } ARRAY|VALUE,  [ 1, [ 2, [ [ 3 ], 4 ] ], 5 ];
46
47        print "$dump\n";
48        # OUTPUT
49        # [ '1', [ '2', [ [ '3' ], '4' ] ], '5' ]
50

DESCRIPTION

52        rmap BLOCK LIST
53
54       Recursively evaluate a BLOCK over a list of data structures (locally
55       setting $_ to each element) and return the list composed of the results
56       of such evaluations.  $_ can be used to modify the elements.
57
58       Data::Rmap currently traverses HASH, ARRAY, SCALAR and GLOB reference
59       types and ignores others.  Depending on which rmap_* wrapper is used,
60       the BLOCK is called for only scalar values, arrays, hashes, references,
61       all elements or a customizable combination.
62
63       The list of data structures is traversed pre-order in a depth-first
64       fashion.  That is, the BLOCK is called for the container reference
65       before is it called for it's elements (although see "recurse" below for
66       post-order).  The values of a hash are traversed in the usual "values"
67       order which may affect some applications.
68
69       If the "cut" subroutine is called in the BLOCK then the traversal stops
70       for that branch, say if you "cut" an array then the code is never
71       called for it's elements (or their sub-elements).  To simultaneously
72       return values and cut, simply pass the return list to cut:
73       "cut('add','to','returned');"
74
75       The first parameter to the BLOCK is an object which maintains the state
76       of the traversal.  Methods available on this object are described in
77       "State Object" below.
78

EXPORTS

80       By default:
81
82        rmap, rmap_all, cut
83
84       Optionally:
85
86        rmap_scalar rmap_hash rmap_array rmap_code rmap_ref rmap_to
87        :types => [ qw(NONE VALUE HASH ARRAY SCALAR REF CODE ALL) ],
88        :all => ... # everything
89

Functions

91       The various names are just wrappers which select when to call the code
92       BLOCK.  rmap_all always calls it, the others are more selective while
93       rmap_to takes an extra parameter permitting you to provide selection
94       criteria.  Furthermore, you can always just rmap_all and skip nodes
95       which are not of interest.
96
97       rmap_to { ... } $want, @data_structures;
98           Most general first.
99
100           Recurse the @data_structures and apply the BLOCK to elements
101           selected by $want.  The $want parameter is the bitwise "or" of
102           whatever types you choose (imported with :types):
103
104            VALUE  - non-reference scalar, eg. 1
105            HASH   - hash reference
106            ARRAY  - array reference
107            SCALAR - scalar refernce, eg. \1
108            REF    - higher-level reference, eg. \\1, \\{}
109                     B<NOT> any reference type, see <Scalar::Util>'s reftype:
110                     perl -MScalar::Util=reftype -le 'print map reftype($_), \1, \\1'
111            GLOB   - glob reference, eg. \*x
112                     (scalar, hash and array recursed, code too as of 0.63)
113            ALL    - all of the above (not CODE)
114            CODE   - code references (as of 0.63)
115            NONE   - none of the above
116
117           So to call the block for arrays and scalar values do:
118
119            use Data::Rmap ':all';         # or qw(:types rmap_to)
120            rmap { ... } ARRAY|VALUE, @data_structures;
121
122           (ALL | CODE) and (ALL & !GLOB) might also be handy.
123
124           The remainder of the wrappers are given in terms of the $want for
125           rmap_to.
126
127       rmap { ... } @list;
128           Recurse and call the BLOCK on non-reference scalar values.  $want =
129           VALUE
130
131       rmap_all BLOCK LIST
132           Recurse and call the BLOCK on everything.  $want = ALL
133
134       rmap_scalar { ... }  @list
135           Recurse and call the BLOCK on non-collection scalars.  $want =
136           VALUE|SCALAR|REF
137
138       rmap_hash
139           Recurse and call the BLOCK on hash refs.  $want = HASH
140
141       rmap_array
142           Recurse and call the BLOCK on array refs.  $want = ARRAY
143
144       rmap_code
145           Recurse and call the BLOCK on code refs.  $want = CODE
146
147       rmap_ref
148           Recurse and call the BLOCK on all "normal" references: $want =
149           HASH|ARRAY|SCALAR|REF
150
151           Note: rmap_ref isn't the same as rmap_to {} REF
152
153       cut(@list)
154           Don't traverse sub-elements and return the @list immediately.  For
155           example, if $_ is an ARRAY reference, then the array's elements are
156           not traversed.
157
158           If there's two paths to an element, both will need to be cut.
159

State Object

161       The first parameter to the BLOCK is an object which maintains most of
162       the traversal state (except current node, which is $_).  You will
163       ignore it most of the time.  The "recurse" method may be useful.  Other
164       methods should only be used in throw away tools, see TODO
165
166       Methods:
167
168       recurse
169           Process child nodes of $_ now and return the result.
170
171           This makes it easier to perform post-order and in-order processing
172           of a structure.  Note that since the same "seen list" is used, the
173           child nodes aren't reprocessed.
174
175       code
176           The code reference of the BLOCK itself.  Possible useful in some
177           situations.
178
179       seen
180           Reference to the HASH used to track where we have visited.  You may
181           want to modify it in some situations (though I haven't yet).
182           Beware circular references.  The (current) convention used for the
183           key is in the source.
184
185       want
186           The $want state described in rmap_to.
187

EXAMPLES

189        # command-line play
190        $ perl -MData::Rmap -le 'print join ":", rmap { $_ } 1,2,[3..5],\\6'
191        1:2:3:4:5:6
192
193
194        # Linearly number questions on a set of pages
195        my $qnum = 1;
196        rmap_hash {
197            $_->{qnum} = $qnum++ if($_->{qn});
198        } @pages;
199
200
201        # Grep recursively, finding ALL objects
202        use Scalar::Util qw(blessed);
203        my @objects = rmap_ref {
204            blessed($_) ? $_ : ();
205        } $data_structure;
206
207
208        # Grep recursively, finding public objects (note the cut)
209        use Scalar::Util qw(blessed);
210        my @objects = rmap_ref {
211            blessed($_) ?  cut($_) : ();
212        } $data_structure;
213
214
215        # Return a modified structure
216        # (result flattening means we must cheat by cloning then modifying)
217        use Storable qw(dclone);
218        use Lingua::EN::Numbers::Easy;
219
220        $words = [ 1, \2, { key => 3 } ];
221        $nums = dclone $words;
222        rmap { $_ = $N{$_} || $_ } $nums;
223
224
225        # Make an assertion about a structure
226        use Data::Dump;
227        rmap_ref {
228           blessed($_) && $_->isa('Question') && defined($_->name)
229               or die "Question doesn't have a name:", dump($_);
230        } @pages;
231
232
233        # Traverse a tree using localize state
234        $tree = [
235            one =>
236            two =>
237            [
238                three_one =>
239                three_two =>
240                [
241                    three_three_one =>
242                ],
243                three_four =>
244            ],
245            four =>
246            [
247                [
248                    five_one_one =>
249                ],
250            ],
251        ];
252
253        @path = ('q');
254        rmap_to {
255            if(ref $_) {
256                local(@path) = (@path, 1); # ARRAY adds a new level to the path
257                $_[0]->recurse(); # does stuff within local(@path)'s scope
258            } else {
259                print join('.', @path), " = $_ \n"; # show the scalar's path
260            }
261            $path[-1]++; # bump last element (even when it was an aref)
262        } ARRAY|VALUE, $tree;
263
264        # OUTPUT
265        # q.1 = one
266        # q.2 = two
267        # q.3.1 = three_one
268        # q.3.2 = three_two
269        # q.3.3.1 = three_three_one
270        # q.3.4 = three_four
271        # q.4 = four
272        # q.5.1.1 = five_one_one
273
274        # replace CODE with "<CODE>"
275        $ perl -MData::Rmap=:all -E 'say join ":", rmap_code { "<CODE>" } sub{},sub{}'
276        <CODE>:<CODE>
277
278        # look inside code refs with PadWalker
279        $ perl -MData::Rmap=:all -MSub::Identify=:all -MPadWalker=:all -MSub::Name
280          use 5.10.0;
281          my $s = sub {}; sub A::a { $s };
282          say join ", ",
283           rmap_code {
284               sub_fullname($_),                       # name string
285               map { $_[0]->recurse } closed_over($_)  # then recurse the sub innards
286           } \*A::a, subname b => sub { $s };
287          # A::a, main::__ANON__, main::b
288

Troubleshooting

290       Beware comma after block:
291
292        rmap { print }, 1..3;
293                      ^-------- bad news, you get an empty list:
294        rmap(sub { print $_; }), 1..3;
295
296       If you don't import a function, perl's confusion may produce:
297
298        $ perl -MData::Rmap -le 'rmap_scalar { print } 1'
299        Can't call method "rmap_scalar" without a package or object reference...
300
301        $ perl -MData::Rmap -le 'rmap_scalar { $_++ } 1'
302        Can't call method "rmap_scalar" without a package or object reference...
303
304       If there's two paths to an element, both will need to be cut.
305
306       If there's two paths to an element, one will be taken randomly when
307       there is an intervening hash.
308
309       Autovivification can lead to "Deep recursion" warnings if you test
310       "exists $_->{this}{that}" instead of "exists $_->{this} && exists
311       $_->{this}{that}" as you may follow a long chain of "this"s
312       Alternatively use the "no autovivification" pragma to avoid this
313       problem.
314

TODO

316       put for @_ in wrapper to allow parameters in a different wrapper, solve
317       localizing problem.
318
319       Store custom localized data about the traversal.  Seems too difficult
320       and ugly when compare to doing it at the call site.  Should support
321       multiple reentrancy so avoid the symbol table.
322
323       "rmap_args { } $data_structure, @args" form to pass parameters.  Could
324       potentially help localizing needs.  (Maybe only recurse last item)
325
326       Benchmark.  Use array based object and/or direct access internally.
327
328       Think about permitting different callback for different types.  The
329       prototype syntax is a bit too flaky....
330
331       Ensure that no memory leaks are possible, leaking the closure.
332

SEE ALSO

334       map, grep, Storable's dclone, Scalar::Util's reftype and blessed
335
336       Faint traces of treemap:
337
338        http://www.perlmonks.org/index.pl?node_id=60829
339
340       Update: various alternatives have appear over the years, Data::Visitor
341       has a list.
342

AUTHOR

344       Brad Bowman <rmap@bereft.net>
345
347       Copyright (c) 2004- Brad Bowman (<rmap@bereft.net>).  All rights
348       reserved.
349
350       This module is free software; you can redistribute it and/or modify it
351       under the same terms as Perl itself.  See perlartistic and perlgpl.
352
353       This program is distributed in the hope that it will be useful, but
354       WITHOUT ANY WARRANTY; without even the implied warranty of
355       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
356
357
358
359perl v5.34.0                      2022-01-21                     Data::Rmap(3)
Impressum