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.54';
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   1384922 use strict;
  51         289  
  51         1953  
94             local $^W = 1;
95 51     51   290 use Carp;
  51         113  
  51         3334  
96 51         3852 use List::Compare::Base::_Auxiliary qw(
97             _subset_subengine
98             _chart_engine_multiple
99             _equivalent_subengine
100             _calc_seen1
101 51     51   10162 );
  51         151  
102 51     51   424 use List::Compare::Base::_Auxiliary qw(:calculate :checker :tester);
  51         142  
  51         10760  
103 51         65013 use List::Compare::Base::_Engine qw(
104             _unique_all_engine
105             _complement_all_engine
106 51     51   8427 );
  51         141  
107              
108              
109             sub get_union {
110 23     23 0 6333 return @{ get_union_ref(@_) };
  23         81  
111             }
112              
113             sub get_union_ref {
114 45     45 0 21275 my ($argref, $unsorted) = _alt_construct_tester(@_);
115             $unsorted
116             ? return _union_engine(_argument_checker($argref))
117 41 100       147 : return [ sort @{_union_engine(_argument_checker($argref))} ];
  22         72  
118             }
119              
120             sub _union_engine {
121 33     33   134 my $seenrefsref = _calc_seen1(@_);
122 33         115 my $unionhashref = _calculate_union_only($seenrefsref);
123 33         67 return [ keys %{$unionhashref} ];
  33         442  
124             }
125              
126             sub get_intersection {
127 26     26 0 17515 return @{ get_intersection_ref(@_) };
  26         105  
128             }
129              
130             sub get_intersection_ref {
131 52     52 0 15755 my ($argref, $unsorted) = _alt_construct_tester(@_);
132             $unsorted
133             ? return _intersection_engine(_argument_checker($argref))
134 48 100       205 : return [ sort @{_intersection_engine(_argument_checker($argref))} ];
  30         100  
135             }
136              
137             sub _intersection_engine {
138 40     40   173 my $seenrefsref = _calc_seen1(@_);
139 120         220 my @vals = sort { scalar(keys(%{$a})) <=> scalar(keys(%{$b})) }
  120         213  
  120         293  
140 40         91 @{$seenrefsref};
  40         187  
141 40         93 my %intersection = map { $_ => 1 } keys %{$vals[0]};
  200         454  
  40         176  
142 40         196 for my $l ( 1..$#vals ) {
143 288         731 %intersection = map { $_ => 1 }
144 512         930 grep { exists $intersection{$_} }
145 88         200 keys %{$vals[$l]};
  88         235  
146             }
147 40         437 return [ keys %intersection ];
148             }
149              
150             sub get_unique {
151 29     29 0 20683 return @{ get_unique_ref(@_) };
  29         188  
152             }
153              
154             sub get_unique_ref {
155 58     58 0 19038 my ($argref, $unsorted) = _alt_construct_tester_3(@_);
156             $unsorted
157             ? return _unique_engine(_argument_checker_3($argref))
158 54 100       206 : return [ sort @{_unique_engine(_argument_checker_3($argref))} ];
  35         105  
159             }
160              
161             sub get_unique_all {
162 17     17 0 11999 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         101 return _unique_all_engine(_argument_checker_3a($argref));
166             }
167              
168             sub _unique_engine {
169 41     41   97 my $index = pop(@_);
170 41         126 my $seenref = _calculate_seen_only(_calc_seen1(@_));
171              
172 41         133 my %seen_in_all_others = ();
173 41         84 my @seenthis = ();
174 41         78 for my $i (keys %{$seenref}) {
  41         134  
175 154 100       338 unless ($i == $index) {
176 113         157 for my $k (keys %{$seenref->{$i}}) {
  113         360  
177 631         1011 $seen_in_all_others{$k}++;
178             }
179             }
180             else {
181 41         85 @seenthis = keys %{$seenref->{$index}};
  41         182  
182             }
183             }
184 41         108 my @unique_to_this_index = ();
185 41         81 for my $s (@seenthis) {
186             push @unique_to_this_index, $s
187 255 100       549 unless $seen_in_all_others{$s};
188             }
189 41         374 return \@unique_to_this_index;
190             }
191              
192             sub get_complement {
193 32     32 0 28706 return @{ get_complement_ref(@_) };
  32         115  
194             }
195              
196             sub get_complement_ref {
197 65     65 0 22758 my ($argref, $unsorted) = _alt_construct_tester_3(@_);
198             $unsorted
199             ? return _complement_engine(_argument_checker_3($argref))
200 61 100       246 : return [ sort @{_complement_engine(_argument_checker_3($argref))} ];
  35         108  
201             }
202              
203             sub get_complement_all {
204 17     17 0 12052 my ($argref, $unsorted) = _alt_construct_tester_3(@_);
205 17         104 return _complement_all_engine(_argument_checker_3a($argref), $unsorted);
206             }
207              
208             sub _complement_engine {
209 48     48   181 my $tested = pop(@_);
210 48         168 my $seenrefsref = _calc_seen1(@_);
211 48         190 my ($unionref, $seenref) = _calculate_union_seen_only($seenrefsref);
212              
213             # Calculate %xcomplement
214             # Inputs: $seenrefsref @union (keys %$unionref)
215 48         93 my (%xcomplement);
216 48         131 for (my $i = 0; $i <= $#{$seenrefsref}; $i++) {
  240         562  
217 192         302 my @complementthis = ();
218 192         252 foreach my $k (keys %{$unionref}) {
  192         534  
219 1856 100       3623 push(@complementthis, $k) unless (exists $seenref->{$i}->{$k});
220             }
221 192         547 $xcomplement{$i} = \@complementthis;
222             }
223 48         91 return [ @{$xcomplement{$tested}} ];
  48         606  
224             }
225              
226             sub get_symmetric_difference {
227 44     44 0 36309 return @{ get_symmetric_difference_ref(@_) };
  44         130  
228             }
229              
230             sub get_symmetric_difference_ref {
231 88     88 0 31815 my ($argref, $unsorted) = _alt_construct_tester(@_);
232             $unsorted
233             ? return _symmetric_difference_engine(_argument_checker($argref))
234 80 100       296 : return [ sort @{_symmetric_difference_engine(_argument_checker($argref))} ];
  44         138  
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   200 my $seenrefsref = _calc_seen1(@_);
240              
241 64         188 my $unionref = _calculate_union_only($seenrefsref);
242              
243 64         198 my $sharedref = _calculate_sharedref($seenrefsref);
244              
245 64         152 my (@symmetric_difference);
246 64         131 for my $k (keys %{$unionref}) {
  64         255  
247 576 100       1254 push(@symmetric_difference, $k) unless exists $sharedref->{$k};
248             }
249 64         706 return \@symmetric_difference;
250             }
251              
252             {
253 51     51   435 no warnings 'once';
  51         104  
  51         41128  
254             *get_symdiff = \&get_symmetric_difference;
255             *get_symdiff_ref = \&get_symmetric_difference_ref;
256             }
257              
258             sub get_shared {
259 22     22 0 16622 return @{ get_shared_ref(@_) };
  22         113  
260             }
261              
262             sub get_shared_ref {
263 44     44 0 16003 my ($argref, $unsorted) = _alt_construct_tester(@_);
264             $unsorted
265             ? return _shared_engine(_argument_checker($argref))
266 40 100       171 : return [ sort @{_shared_engine(_argument_checker($argref))} ];
  22         66  
267             }
268              
269             sub _shared_engine {
270 32     32   110 my $seenrefsref = _calc_seen1(@_);
271              
272 32         131 my $sharedref = _calculate_sharedref($seenrefsref);
273 32         80 return [ keys %{$sharedref} ];
  32         362  
274             }
275              
276             sub get_nonintersection {
277 22     22 0 18893 return @{ get_nonintersection_ref(@_) };
  22         101  
278             }
279              
280             sub get_nonintersection_ref {
281 44     44 0 15640 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         65  
285             }
286              
287             sub _nonintersection_engine {
288 32     32   130 my $seenrefsref = _calc_seen1(@_);
289 32         137 my $unionref =
290             _calculate_union_only($seenrefsref);
291 112         159 my @vals = sort { scalar(keys(%{$a})) <=> scalar(keys(%{$b})) }
  112         197  
  112         240  
292 32         87 @{$seenrefsref};
  32         144  
293 32         125 my %intersection = map { $_ => 1 } keys %{$vals[0]};
  176         403  
  32         105  
294 32         144 for my $l ( 1..$#vals ) {
295 288         621 %intersection = map { $_ => 1 }
296 480         875 grep { exists $intersection{$_} }
297 80         140 keys %{$vals[$l]};
  80         208  
298             }
299             # Calculate nonintersection
300             # Inputs: @union (keys %$unionref) %intersection
301 32         104 my (@nonintersection);
302 32         72 for my $k (keys %{$unionref}) {
  32         138  
303 288 100       624 push(@nonintersection, $k) unless exists $intersection{$k};
304             }
305 32         309 return \@nonintersection;
306             }
307              
308             sub is_LsubsetR {
309 44     44 0 18175 my $argref = _alt_construct_tester_4(@_);
310 42         150 return _is_LsubsetR_engine(_argument_checker_4($argref));
311             }
312              
313             sub _is_LsubsetR_engine {
314 38     38   83 my $testedref = pop(@_);
315 38         115 my $xsubsetref = _subset_engine(@_);
316 38         79 return ${$xsubsetref}[${$testedref}[0]][${$testedref}[1]];
  38         161  
  38         78  
  38         431  
317             }
318              
319             sub is_RsubsetL {
320 22     22 0 8060 my $argref = _alt_construct_tester_4(@_);
321 20         87 return _is_RsubsetL_engine(_argument_checker_4($argref));
322             }
323              
324             sub _is_RsubsetL_engine {
325 18     18   36 my $testedref = pop(@_);
326 18         43 my $xsubsetref = _subset_engine(@_);
327 18         33 return ${$xsubsetref}[${$testedref}[1]][${$testedref}[0]];
  18         85  
  18         38  
  18         52  
328             }
329              
330             sub _subset_engine {
331 56     56   149 my $seenrefsref = _calc_seen1(@_);
332 56         164 my $xsubsetref = _subset_subengine($seenrefsref);
333 56         165 return $xsubsetref;
334             }
335              
336             sub is_LequivalentR {
337 46     46 0 17140 my $argref = _alt_construct_tester_4(@_);
338 42         149 return _is_LequivalentR_engine(_argument_checker_4($argref));
339             }
340              
341 51     51   449 { no warnings 'once'; *is_LeqvlntR = \&is_LequivalentR; }
  51         140  
  51         71110  
342              
343             sub _is_LequivalentR_engine {
344 36     36   74 my $testedref = pop(@_);
345 36         97 my $seenrefsref = _calc_seen1(@_);
346 36         108 my $xequivalentref = _equivalent_subengine($seenrefsref);
347 36         72 return ${$xequivalentref}[${$testedref}[1]][${$testedref}[0]];
  36         176  
  36         85  
  36         101  
348             }
349              
350             sub is_LdisjointR {
351 34     34 0 10717 my $argref = _alt_construct_tester_4(@_);
352 32         121 return _is_LdisjointR_engine(_argument_checker_4($argref));
353             }
354              
355             sub _is_LdisjointR_engine {
356 28     28   61 my $testedref = pop(@_);
357 28         77 my $seenrefsref = _calc_seen1(@_);
358 28         76 my $disjoint = 1; # start out assuming disjoint status
359 28         51 OUTER: for my $k (keys %{$seenrefsref->[$testedref->[0]]}) {
  28         161  
360 55 100       174 if ($seenrefsref->[$testedref->[1]]->{$k}) {
361 20         57 $disjoint = 0;
362 20         49 last OUTER;
363             }
364             }
365 28         155 return $disjoint;
366             }
367              
368             sub print_subset_chart {
369 11     11 0 22809 my $argref = _alt_construct_tester_5(@_);
370 8         34 _print_subset_chart_engine(_argument_checker($argref));
371             }
372              
373             sub _print_subset_chart_engine {
374 8     8   54 my $seenrefsref = _calc_seen1(@_);
375 8         47 my $xsubsetref = _subset_subengine($seenrefsref);
376 8         47 my $title = 'Subset';
377 8         46 _chart_engine_multiple($xsubsetref, $title);
378             }
379              
380             sub print_equivalence_chart {
381 11     11 0 44652 my $argref = _alt_construct_tester_5(@_);
382 8         78 _print_equivalence_chart_engine(_argument_checker($argref));
383             }
384              
385             sub _print_equivalence_chart_engine {
386 8     8   36 my $seenrefsref = _calc_seen1(@_);
387 8         54 my $xequivalentref = _equivalent_subengine($seenrefsref);
388 8         37 my $title = 'Equivalence';
389 8         48 _chart_engine_multiple($xequivalentref, $title);
390             }
391              
392             sub is_member_which {
393 92     92 0 18106 return @{ is_member_which_ref(@_) };
  92         206  
394             }
395              
396             sub is_member_which_ref {
397 184     184 0 22438 my $argref = _alt_construct_tester_1(@_);
398 178         397 return _is_member_which_engine(_argument_checker_1($argref));
399             }
400              
401             sub _is_member_which_engine {
402 176     176   297 my $arg = pop(@_);
403 176         401 my $seenrefsref = _calc_seen1(@_);
404 176         389 my $seenref = _calculate_seen_only($seenrefsref);
405 176         278 my (@found);
406 176         256 foreach (sort keys %{$seenref}) {
  176         668  
407 616 100       866 push @found, $_ if (exists ${$seenref}{$_}{$arg});
  616         1561  
408             }
409 176         1115 return \@found;
410             }
411              
412             sub is_member_any {
413 92     92 0 14889 my $argref = _alt_construct_tester_1(@_);
414 89         240 return _is_member_any_engine(_argument_checker_1($argref));
415             }
416              
417             sub _is_member_any_engine {
418 88     88   167 my $tested = pop(@_);
419 88         190 my $seenrefsref = _calc_seen1(@_);
420 88         214 my $seenref = _calculate_seen_only($seenrefsref);
421 88         137 my ($k);
422 88         132 while ( $k = each %{$seenref} ) {
  175         471  
423 159 100       233 return 1 if (defined ${$seenref}{$k}{$tested});
  159         666  
424             }
425 16         89 return 0;
426             }
427              
428             sub are_members_which {
429 13     13 0 21504 my $argref = _alt_construct_tester_2(@_);
430 9         43 return _are_members_which_engine(_argument_checker_2($argref));
431             }
432              
433             sub _are_members_which_engine {
434 8     8   36 my $testedref = pop(@_);
435 8         17 my @tested = @{$testedref};
  8         36  
436 8         47 my $seenrefsref = _calc_seen1(@_);
437 8         33 my $seenref = _calculate_seen_only($seenrefsref);
438 8         17 my (%found);
439 8         61 for (my $i=0; $i<=$#tested; $i++) {
440 88         133 my (@not_found);
441 88         115 foreach (sort keys %{$seenref}) {
  88         240  
442 308         368 exists ${${$seenref}{$_}}{$tested[$i]}
  308         708  
443 308 100       413 ? push @{$found{$tested[$i]}}, $_
  164         395  
444             : push @not_found, $_;
445             }
446 88 100       156 $found{$tested[$i]} = [] if (@not_found == keys %{$seenref});
  88         332  
447             }
448 8         82 return \%found;
449             }
450              
451             sub are_members_any {
452 13     13 0 8176 my $argref = _alt_construct_tester_2(@_);
453 9         66 return _are_members_any_engine(_argument_checker_2($argref));
454             }
455              
456             sub _are_members_any_engine {
457 8     8   25 my $testedref = pop(@_);
458 8         51 my @tested = @{$testedref};
  8         35  
459 8         65 my $seenrefsref = _calc_seen1(@_);
460 8         36 my $seenref = _calculate_seen_only($seenrefsref);
461 8         22 my (%present);
462 8         51 for (my $i=0; $i<=$#tested; $i++) {
463 88         138 foreach (keys %{$seenref}) {
  88         193  
464 308 100       588 unless (defined $present{$tested[$i]}) {
465 153 100       194 $present{$tested[$i]} = 1 if ${$seenref}{$_}{$tested[$i]};
  153         428  
466             }
467             }
468 88 100       325 $present{$tested[$i]} = 0 if (! defined $present{$tested[$i]});
469             }
470 8         83 return \%present;
471             }
472              
473             sub get_bag {
474 22     22 0 15573 return @{ get_bag_ref(@_) };
  22         91  
475             }
476              
477             sub get_bag_ref {
478 44     44 0 17304 my ($argref, $unsorted) = _alt_construct_tester(@_);
479             $unsorted
480             ? return _bag_engine(_argument_checker($argref))
481 40 100       249 : return [ sort @{_bag_engine(_argument_checker($argref))} ];
  22         107  
482             }
483              
484             sub _bag_engine {
485 32     32   101 my @listrefs = @_;
486 32         64 my (@bag);
487 32 100       116 if (ref($listrefs[0]) eq 'ARRAY') {
488 16         50 foreach my $lref (@listrefs) {
489 56         89 foreach my $el (@{$lref}) {
  56         99  
490 384         647 push(@bag, $el);
491             }
492             }
493             } else {
494 16         42 foreach my $lref (@listrefs) {
495 56         80 foreach my $key (keys %{$lref}) {
  56         123  
496 328         447 for (my $j=1; $j <= ${$lref}{$key}; $j++) {
  712         1441  
497 384         652 push(@bag, $key);
498             }
499             }
500             }
501             }
502 32         431 return \@bag;
503             }
504              
505             sub get_version {
506 8     8 0 3417 return $List::Compare::Functional::VERSION;
507             }
508              
509             1;
510              
511             __END__