File Coverage

blib/lib/List/Compare/Functional.pm
Criterion Covered Total %
statement 270 270 100.0
branch 44 44 100.0
condition n/a
subroutine 56 56 100.0
pod 0 30 0.0
total 370 400 92.5


line stmt bran cond sub pod time code
1             package List::Compare::Functional;
2             our $VERSION = '0.55';
3             our @ISA = qw(Exporter);
4             our @EXPORT_OK = qw|
5             get_intersection
6             get_intersection_ref
7             get_union
8             get_union_ref
9             get_unique
10             get_unique_ref
11             get_unique_all
12             get_complement
13             get_complement_ref
14             get_complement_all
15             get_symmetric_difference
16             get_symmetric_difference_ref
17             is_LsubsetR
18             is_RsubsetL
19             is_LequivalentR
20             is_LdisjointR
21             is_member_which
22             is_member_which_ref
23             are_members_which
24             is_member_any
25             are_members_any
26             print_subset_chart
27             print_equivalence_chart
28             get_shared
29             get_shared_ref
30             get_nonintersection
31             get_nonintersection_ref
32             get_symdiff
33             get_symdiff_ref
34             is_LeqvlntR
35             get_bag
36             get_bag_ref
37             get_version
38             |;
39             our %EXPORT_TAGS = (
40             main => [ qw(
41             get_intersection
42             get_union
43             get_unique
44             get_complement
45             get_symmetric_difference
46             is_LsubsetR
47             ) ],
48             mainrefs => [ qw(
49             get_intersection_ref
50             get_union_ref
51             get_unique_ref
52             get_complement_ref
53             get_symmetric_difference_ref
54             ) ],
55             originals => [ qw(
56             get_intersection
57             get_intersection_ref
58             get_union
59             get_union_ref
60             get_unique
61             get_unique_ref
62             get_unique_all
63             get_complement
64             get_complement_ref
65             get_complement_all
66             get_symmetric_difference
67             get_symmetric_difference_ref
68             get_shared
69             get_shared_ref
70             get_nonintersection
71             get_nonintersection_ref
72             is_LsubsetR
73             is_RsubsetL
74             is_LequivalentR
75             is_LdisjointR
76             is_member_which
77             is_member_which_ref
78             are_members_which
79             is_member_any
80             are_members_any
81             print_subset_chart
82             print_equivalence_chart
83             get_bag
84             get_bag_ref
85             get_version
86             ) ],
87             aliases => [ qw(
88             get_symdiff
89             get_symdiff_ref
90             is_LeqvlntR
91             ) ],
92             );
93 51     51   1348335 use strict;
  51         283  
  51         1926  
94             local $^W = 1;
95 51     51   332 use Carp;
  51         124  
  51         3355  
96 51         3910 use List::Compare::Base::_Auxiliary qw(
97             _subset_subengine
98             _chart_engine_multiple
99             _equivalent_subengine
100             _calc_seen1
101 51     51   9730 );
  51         122  
102 51     51   442 use List::Compare::Base::_Auxiliary qw(:calculate :checker :tester);
  51         150  
  51         10584  
103 51         65401 use List::Compare::Base::_Engine qw(
104             _unique_all_engine
105             _complement_all_engine
106 51     51   8935 );
  51         122  
107              
108              
109             sub get_union {
110 23     23 0 6332 return @{ get_union_ref(@_) };
  23         84  
111             }
112              
113             sub get_union_ref {
114 45     45 0 21228 my ($argref, $unsorted) = _alt_construct_tester(@_);
115             $unsorted
116             ? return _union_engine(_argument_checker($argref))
117 41 100       143 : return [ sort @{_union_engine(_argument_checker($argref))} ];
  22         69  
118             }
119              
120             sub _union_engine {
121 33     33   124 my $seenrefsref = _calc_seen1(@_);
122 33         119 my $unionhashref = _calculate_union_only($seenrefsref);
123 33         61 return [ keys %{$unionhashref} ];
  33         405  
124             }
125              
126             sub get_intersection {
127 26     26 0 17114 return @{ get_intersection_ref(@_) };
  26         99  
128             }
129              
130             sub get_intersection_ref {
131 52     52 0 15670 my ($argref, $unsorted) = _alt_construct_tester(@_);
132             $unsorted
133             ? return _intersection_engine(_argument_checker($argref))
134 48 100       190 : return [ sort @{_intersection_engine(_argument_checker($argref))} ];
  30         111  
135             }
136              
137             sub _intersection_engine {
138 40     40   131 my $seenrefsref = _calc_seen1(@_);
139 120         183 my @vals = sort { scalar(keys(%{$a})) <=> scalar(keys(%{$b})) }
  120         208  
  120         320  
140 40         84 @{$seenrefsref};
  40         192  
141 40         86 my %intersection = map { $_ => 1 } keys %{$vals[0]};
  200         431  
  40         176  
142 40         188 for my $l ( 1..$#vals ) {
143 288         712 %intersection = map { $_ => 1 }
144 512         896 grep { exists $intersection{$_} }
145 88         175 keys %{$vals[$l]};
  88         227  
146             }
147 40         394 return [ keys %intersection ];
148             }
149              
150             sub get_unique {
151 29     29 0 20403 return @{ get_unique_ref(@_) };
  29         219  
152             }
153              
154             sub get_unique_ref {
155 58     58 0 19334 my ($argref, $unsorted) = _alt_construct_tester_3(@_);
156             $unsorted
157             ? return _unique_engine(_argument_checker_3($argref))
158 54 100       183 : return [ sort @{_unique_engine(_argument_checker_3($argref))} ];
  35         116  
159             }
160              
161             sub get_unique_all {
162 17     17 0 11939 my ($argref, $unsorted) = _alt_construct_tester_3(@_);
163             # currently it doesn't appear that &_unique_all_engine can make use of
164             # $unsorted
165 17         78 return _unique_all_engine(_argument_checker_3a($argref));
166             }
167              
168             sub _unique_engine {
169 41     41   99 my $index = pop(@_);
170 41         134 my $seenref = _calculate_seen_only(_calc_seen1(@_));
171              
172 41         126 my %seen_in_all_others = ();
173 41         76 my @seenthis = ();
174 41         79 for my $i (keys %{$seenref}) {
  41         137  
175 154 100       347 unless ($i == $index) {
176 113         161 for my $k (keys %{$seenref->{$i}}) {
  113         316  
177 631         1025 $seen_in_all_others{$k}++;
178             }
179             }
180             else {
181 41         81 @seenthis = keys %{$seenref->{$index}};
  41         172  
182             }
183             }
184 41         91 my @unique_to_this_index = ();
185 41         96 for my $s (@seenthis) {
186             push @unique_to_this_index, $s
187 255 100       571 unless $seen_in_all_others{$s};
188             }
189 41         363 return \@unique_to_this_index;
190             }
191              
192             sub get_complement {
193 32     32 0 28818 return @{ get_complement_ref(@_) };
  32         97  
194             }
195              
196             sub get_complement_ref {
197 65     65 0 22881 my ($argref, $unsorted) = _alt_construct_tester_3(@_);
198             $unsorted
199             ? return _complement_engine(_argument_checker_3($argref))
200 61 100       243 : return [ sort @{_complement_engine(_argument_checker_3($argref))} ];
  35         101  
201             }
202              
203             sub get_complement_all {
204 17     17 0 12020 my ($argref, $unsorted) = _alt_construct_tester_3(@_);
205 17         84 return _complement_all_engine(_argument_checker_3a($argref), $unsorted);
206             }
207              
208             sub _complement_engine {
209 48     48   115 my $tested = pop(@_);
210 48         137 my $seenrefsref = _calc_seen1(@_);
211 48         168 my ($unionref, $seenref) = _calculate_union_seen_only($seenrefsref);
212              
213             # Calculate %xcomplement
214             # Inputs: $seenrefsref @union (keys %$unionref)
215 48         107 my (%xcomplement);
216 48         108 for (my $i = 0; $i <= $#{$seenrefsref}; $i++) {
  240         526  
217 192         292 my @complementthis = ();
218 192         244 foreach my $k (keys %{$unionref}) {
  192         578  
219 1856 100       3686 push(@complementthis, $k) unless (exists $seenref->{$i}->{$k});
220             }
221 192         486 $xcomplement{$i} = \@complementthis;
222             }
223 48         83 return [ @{$xcomplement{$tested}} ];
  48         565  
224             }
225              
226             sub get_symmetric_difference {
227 44     44 0 35059 return @{ get_symmetric_difference_ref(@_) };
  44         142  
228             }
229              
230             sub get_symmetric_difference_ref {
231 88     88 0 30691 my ($argref, $unsorted) = _alt_construct_tester(@_);
232             $unsorted
233             ? return _symmetric_difference_engine(_argument_checker($argref))
234 80 100       269 : return [ sort @{_symmetric_difference_engine(_argument_checker($argref))} ];
  44         110  
235             }
236              
237             sub _symmetric_difference_engine {
238             # Get those items which do not appear in more than one of several lists (their symmetric_difference);
239 64     64   182 my $seenrefsref = _calc_seen1(@_);
240              
241 64         199 my $unionref = _calculate_union_only($seenrefsref);
242              
243 64         178 my $sharedref = _calculate_sharedref($seenrefsref);
244              
245 64         114 my (@symmetric_difference);
246 64         102 for my $k (keys %{$unionref}) {
  64         209  
247 576 100       1136 push(@symmetric_difference, $k) unless exists $sharedref->{$k};
248             }
249 64         606 return \@symmetric_difference;
250             }
251              
252             {
253 51     51   446 no warnings 'once';
  51         113  
  51         41307  
254             *get_symdiff = \&get_symmetric_difference;
255             *get_symdiff_ref = \&get_symmetric_difference_ref;
256             }
257              
258             sub get_shared {
259 22     22 0 16615 return @{ get_shared_ref(@_) };
  22         76  
260             }
261              
262             sub get_shared_ref {
263 44     44 0 16332 my ($argref, $unsorted) = _alt_construct_tester(@_);
264             $unsorted
265             ? return _shared_engine(_argument_checker($argref))
266 40 100       161 : return [ sort @{_shared_engine(_argument_checker($argref))} ];
  22         84  
267             }
268              
269             sub _shared_engine {
270 32     32   112 my $seenrefsref = _calc_seen1(@_);
271              
272 32         112 my $sharedref = _calculate_sharedref($seenrefsref);
273 32         65 return [ keys %{$sharedref} ];
  32         356  
274             }
275              
276             sub get_nonintersection {
277 22     22 0 18312 return @{ get_nonintersection_ref(@_) };
  22         90  
278             }
279              
280             sub get_nonintersection_ref {
281 44     44 0 15580 my ($argref, $unsorted) = _alt_construct_tester(@_);
282             $unsorted
283             ? return _nonintersection_engine(_argument_checker($argref))
284 40 100       189 : return [ sort @{_nonintersection_engine(_argument_checker($argref))} ];
  22         78  
285             }
286              
287             sub _nonintersection_engine {
288 32     32   107 my $seenrefsref = _calc_seen1(@_);
289 32         112 my $unionref =
290             _calculate_union_only($seenrefsref);
291 112         172 my @vals = sort { scalar(keys(%{$a})) <=> scalar(keys(%{$b})) }
  112         191  
  112         303  
292 32         73 @{$seenrefsref};
  32         161  
293 32         75 my %intersection = map { $_ => 1 } keys %{$vals[0]};
  176         356  
  32         115  
294 32         134 for my $l ( 1..$#vals ) {
295 288         593 %intersection = map { $_ => 1 }
296 480         852 grep { exists $intersection{$_} }
297 80         123 keys %{$vals[$l]};
  80         209  
298             }
299             # Calculate nonintersection
300             # Inputs: @union (keys %$unionref) %intersection
301 32         67 my (@nonintersection);
302 32         85 for my $k (keys %{$unionref}) {
  32         121  
303 288 100       718 push(@nonintersection, $k) unless exists $intersection{$k};
304             }
305 32         306 return \@nonintersection;
306             }
307              
308             sub is_LsubsetR {
309 44     44 0 18066 my $argref = _alt_construct_tester_4(@_);
310 42         135 return _is_LsubsetR_engine(_argument_checker_4($argref));
311             }
312              
313             sub _is_LsubsetR_engine {
314 38     38   90 my $testedref = pop(@_);
315 38         98 my $xsubsetref = _subset_engine(@_);
316 38         66 return ${$xsubsetref}[${$testedref}[0]][${$testedref}[1]];
  38         163  
  38         74  
  38         70  
317             }
318              
319             sub is_RsubsetL {
320 22     22 0 7912 my $argref = _alt_construct_tester_4(@_);
321 20         59 return _is_RsubsetL_engine(_argument_checker_4($argref));
322             }
323              
324             sub _is_RsubsetL_engine {
325 18     18   36 my $testedref = pop(@_);
326 18         49 my $xsubsetref = _subset_engine(@_);
327 18         33 return ${$xsubsetref}[${$testedref}[1]][${$testedref}[0]];
  18         66  
  18         46  
  18         29  
328             }
329              
330             sub _subset_engine {
331 56     56   154 my $seenrefsref = _calc_seen1(@_);
332 56         154 my $xsubsetref = _subset_subengine($seenrefsref);
333 56         160 return $xsubsetref;
334             }
335              
336             sub is_LequivalentR {
337 46     46 0 16667 my $argref = _alt_construct_tester_4(@_);
338 42         120 return _is_LequivalentR_engine(_argument_checker_4($argref));
339             }
340              
341 51     51   435 { no warnings 'once'; *is_LeqvlntR = \&is_LequivalentR; }
  51         154  
  51         70551  
342              
343             sub _is_LequivalentR_engine {
344 36     36   69 my $testedref = pop(@_);
345 36         100 my $seenrefsref = _calc_seen1(@_);
346 36         119 my $xequivalentref = _equivalent_subengine($seenrefsref);
347 36         61 return ${$xequivalentref}[${$testedref}[1]][${$testedref}[0]];
  36         189  
  36         81  
  36         110  
348             }
349              
350             sub is_LdisjointR {
351 34     34 0 10534 my $argref = _alt_construct_tester_4(@_);
352 32         107 return _is_LdisjointR_engine(_argument_checker_4($argref));
353             }
354              
355             sub _is_LdisjointR_engine {
356 28     28   60 my $testedref = pop(@_);
357 28         73 my $seenrefsref = _calc_seen1(@_);
358 28         74 my $disjoint = 1; # start out assuming disjoint status
359 28         55 OUTER: for my $k (keys %{$seenrefsref->[$testedref->[0]]}) {
  28         162  
360 55 100       138 if ($seenrefsref->[$testedref->[1]]->{$k}) {
361 20         34 $disjoint = 0;
362 20         49 last OUTER;
363             }
364             }
365 28         119 return $disjoint;
366             }
367              
368             sub print_subset_chart {
369 11     11 0 16909 my $argref = _alt_construct_tester_5(@_);
370 8         38 _print_subset_chart_engine(_argument_checker($argref));
371             }
372              
373             sub _print_subset_chart_engine {
374 8     8   35 my $seenrefsref = _calc_seen1(@_);
375 8         46 my $xsubsetref = _subset_subengine($seenrefsref);
376 8         26 my $title = 'Subset';
377 8         45 _chart_engine_multiple($xsubsetref, $title);
378             }
379              
380             sub print_equivalence_chart {
381 11     11 0 19446 my $argref = _alt_construct_tester_5(@_);
382 8         67 _print_equivalence_chart_engine(_argument_checker($argref));
383             }
384              
385             sub _print_equivalence_chart_engine {
386 8     8   33 my $seenrefsref = _calc_seen1(@_);
387 8         38 my $xequivalentref = _equivalent_subengine($seenrefsref);
388 8         19 my $title = 'Equivalence';
389 8         42 _chart_engine_multiple($xequivalentref, $title);
390             }
391              
392             sub is_member_which {
393 92     92 0 12239 return @{ is_member_which_ref(@_) };
  92         187  
394             }
395              
396             sub is_member_which_ref {
397 184     184 0 21888 my $argref = _alt_construct_tester_1(@_);
398 178         387 return _is_member_which_engine(_argument_checker_1($argref));
399             }
400              
401             sub _is_member_which_engine {
402 176     176   282 my $arg = pop(@_);
403 176         413 my $seenrefsref = _calc_seen1(@_);
404 176         381 my $seenref = _calculate_seen_only($seenrefsref);
405 176         267 my (@found);
406 176         242 foreach (sort keys %{$seenref}) {
  176         612  
407 616 100       768 push @found, $_ if (exists ${$seenref}{$_}{$arg});
  616         1436  
408             }
409 176         1091 return \@found;
410             }
411              
412             sub is_member_any {
413 92     92 0 14385 my $argref = _alt_construct_tester_1(@_);
414 89         242 return _is_member_any_engine(_argument_checker_1($argref));
415             }
416              
417             sub _is_member_any_engine {
418 88     88   143 my $tested = pop(@_);
419 88         219 my $seenrefsref = _calc_seen1(@_);
420 88         204 my $seenref = _calculate_seen_only($seenrefsref);
421 88         124 my ($k);
422 88         128 while ( $k = each %{$seenref} ) {
  171         456  
423 155 100       230 return 1 if (defined ${$seenref}{$k}{$tested});
  155         676  
424             }
425 16         89 return 0;
426             }
427              
428             sub are_members_which {
429 13     13 0 21312 my $argref = _alt_construct_tester_2(@_);
430 9         50 return _are_members_which_engine(_argument_checker_2($argref));
431             }
432              
433             sub _are_members_which_engine {
434 8     8   34 my $testedref = pop(@_);
435 8         19 my @tested = @{$testedref};
  8         54  
436 8         42 my $seenrefsref = _calc_seen1(@_);
437 8         34 my $seenref = _calculate_seen_only($seenrefsref);
438 8         41 my (%found);
439 8         57 for (my $i=0; $i<=$#tested; $i++) {
440 88         128 my (@not_found);
441 88         116 foreach (sort keys %{$seenref}) {
  88         241  
442 308         348 exists ${${$seenref}{$_}}{$tested[$i]}
  308         700  
443 308 100       396 ? push @{$found{$tested[$i]}}, $_
  164         402  
444             : push @not_found, $_;
445             }
446 88 100       146 $found{$tested[$i]} = [] if (@not_found == keys %{$seenref});
  88         289  
447             }
448 8         77 return \%found;
449             }
450              
451             sub are_members_any {
452 13     13 0 8011 my $argref = _alt_construct_tester_2(@_);
453 9         40 return _are_members_any_engine(_argument_checker_2($argref));
454             }
455              
456             sub _are_members_any_engine {
457 8     8   33 my $testedref = pop(@_);
458 8         20 my @tested = @{$testedref};
  8         44  
459 8         36 my $seenrefsref = _calc_seen1(@_);
460 8         33 my $seenref = _calculate_seen_only($seenrefsref);
461 8         30 my (%present);
462 8         50 for (my $i=0; $i<=$#tested; $i++) {
463 88         120 foreach (keys %{$seenref}) {
  88         191  
464 308 100       579 unless (defined $present{$tested[$i]}) {
465 143 100       176 $present{$tested[$i]} = 1 if ${$seenref}{$_}{$tested[$i]};
  143         397  
466             }
467             }
468 88 100       278 $present{$tested[$i]} = 0 if (! defined $present{$tested[$i]});
469             }
470 8         77 return \%present;
471             }
472              
473             sub get_bag {
474 22     22 0 15970 return @{ get_bag_ref(@_) };
  22         101  
475             }
476              
477             sub get_bag_ref {
478 44     44 0 17227 my ($argref, $unsorted) = _alt_construct_tester(@_);
479             $unsorted
480             ? return _bag_engine(_argument_checker($argref))
481 40 100       159 : return [ sort @{_bag_engine(_argument_checker($argref))} ];
  22         60  
482             }
483              
484             sub _bag_engine {
485 32     32   96 my @listrefs = @_;
486 32         73 my (@bag);
487 32 100       108 if (ref($listrefs[0]) eq 'ARRAY') {
488 16         37 foreach my $lref (@listrefs) {
489 56         91 foreach my $el (@{$lref}) {
  56         120  
490 384         641 push(@bag, $el);
491             }
492             }
493             } else {
494 16         38 foreach my $lref (@listrefs) {
495 56         84 foreach my $key (keys %{$lref}) {
  56         116  
496 328         437 for (my $j=1; $j <= ${$lref}{$key}; $j++) {
  712         1357  
497 384         629 push(@bag, $key);
498             }
499             }
500             }
501             }
502 32         399 return \@bag;
503             }
504              
505             sub get_version {
506 8     8 0 3157 return $List::Compare::Functional::VERSION;
507             }
508              
509             1;
510              
511             __END__