line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package NestedMap; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
require Exporter; |
4
|
|
|
|
|
|
|
@ISA = qw(Exporter); |
5
|
|
|
|
|
|
|
@EXPORT = qw(nestedmap); |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
$VERSION = '1.0'; |
8
|
|
|
|
|
|
|
|
9
|
1
|
|
|
1
|
|
883
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
36
|
|
10
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
124
|
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
=head1 NAME |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
NestedMap - a module to make nesting map{}s inside map{}s easier |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
=head1 SYNOPSIS |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
# show all combinations of (A,B,C) (a,b,c) and (1,2,3) |
19
|
|
|
|
|
|
|
print join("\n", |
20
|
|
|
|
|
|
|
nestedmap { |
21
|
|
|
|
|
|
|
nestedmap { |
22
|
|
|
|
|
|
|
nestedmap { |
23
|
|
|
|
|
|
|
join('',@NestedMap::stack[0..2]) |
24
|
|
|
|
|
|
|
} qw(A B C) |
25
|
|
|
|
|
|
|
} qw(a b c) |
26
|
|
|
|
|
|
|
} qw(1 2 3) |
27
|
|
|
|
|
|
|
); |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
# a zip() function for any number of lists of varying length |
30
|
|
|
|
|
|
|
sub zipn { |
31
|
|
|
|
|
|
|
my @args = @_; |
32
|
|
|
|
|
|
|
[ |
33
|
|
|
|
|
|
|
nestedmap { |
34
|
|
|
|
|
|
|
nestedmap { |
35
|
|
|
|
|
|
|
defined($args[$_][$NestedMap::stack[1]]) ? |
36
|
|
|
|
|
|
|
$args[$_][$NestedMap::stack[1]] : |
37
|
|
|
|
|
|
|
'' |
38
|
|
|
|
|
|
|
} 0..$#args |
39
|
|
|
|
|
|
|
} 0 .. max(map { $#{$_[$_]} } 0..$#args) |
40
|
|
|
|
|
|
|
] |
41
|
|
|
|
|
|
|
} |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
NB - older versions of perl may not like the code blocks I use in these |
44
|
|
|
|
|
|
|
examples. You may have to use: |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
nestedmap sub { ... }, @list; |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
instead of |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
nestedmap { ... } @list; |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
See the test suite for examples of the above code modified to use that |
53
|
|
|
|
|
|
|
syntax. |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
=head1 DESCRIPTION |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
Perl's map{} function is very useful, but ain't so great when you try to |
58
|
|
|
|
|
|
|
put map{}s inside map{}s, as inner maps can have no idea what the outer |
59
|
|
|
|
|
|
|
map{}s are doing. NestedMap solves that, by maintaining a stack of all |
60
|
|
|
|
|
|
|
the nested map{}s' ideas of what $_ is. It's useful if you want to |
61
|
|
|
|
|
|
|
iterate over lists of lists. |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
It exports one function into your namespace ... |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
=over 4 |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
=item nestedmap |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
This function takes any number of arguments, the first of which must be |
70
|
|
|
|
|
|
|
a coderef (ie, either a reference to a subroutine, or an anonymous |
71
|
|
|
|
|
|
|
subroutine). That subroutine should take one argument. It will be |
72
|
|
|
|
|
|
|
called once for each of the remaining arguments given to nestedmap(). |
73
|
|
|
|
|
|
|
The return value of nestedmap() is a list of all the return values of |
74
|
|
|
|
|
|
|
the user-supplied subroutine Within your subroutine, $_ is available |
75
|
|
|
|
|
|
|
just like in an ordinary map{}. There is also an array called |
76
|
|
|
|
|
|
|
@NestedMap::stack which lets you get at the 'parent' nestedmaps' values |
77
|
|
|
|
|
|
|
of $_. The first element (element 0) is your own $_, the second is the |
78
|
|
|
|
|
|
|
parent's, the third is the grandparent's, and so on. Yes, you can change |
79
|
|
|
|
|
|
|
them. That would be considered evil. And funny. |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
=back |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
=head1 HOW IT DIFFERS FROM map{} |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
Because nestedmap() is a subroutine, as is the user-supplied function, |
86
|
|
|
|
|
|
|
then unlike with map{} (which is a perl built-in) the value of @_ will not |
87
|
|
|
|
|
|
|
remain the same inside a pile of nestedmap()s. If you want to refer to the |
88
|
|
|
|
|
|
|
same @_ throughout, then you will need to assign @_ to another variable |
89
|
|
|
|
|
|
|
first. See the zipn() example in the synopsis above. |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
=head1 BUGS |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
No bugs are known, but if you find any please let me know, and send a test |
94
|
|
|
|
|
|
|
case. |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
=head1 FEEDBACK |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
I welcome feedback about my code, including constructive criticism. And, |
99
|
|
|
|
|
|
|
while this is free software (both free-as-in-beer and free-as-in-speech) I |
100
|
|
|
|
|
|
|
also welcome payment. In particular, your bug reports will get moved to |
101
|
|
|
|
|
|
|
the front of the queue if you buy me something from my wishlist, which can |
102
|
|
|
|
|
|
|
be found at L. |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
=head1 AUTHOR |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
David Cantrell EFE |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
=head1 COPYRIGHT |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
Copyright 2003 David Cantrell |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
This module is free-as-in-speech software, and may be used, distributed, |
113
|
|
|
|
|
|
|
and modified under the same terms as Perl itself. |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
=cut |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
sub nestedmap(&@) { |
118
|
18
|
|
|
18
|
1
|
219
|
my $f = shift; |
119
|
55
|
|
|
|
|
273
|
map { |
120
|
18
|
|
|
|
|
26
|
local @NestedMap::stack = ($_, @NestedMap::stack); |
121
|
55
|
|
|
|
|
109
|
$f->($_); |
122
|
|
|
|
|
|
|
} @_ |
123
|
|
|
|
|
|
|
} |