File Coverage

blib/lib/List/Compare/Functional.pm
Criterion Covered Total %
statement 264 264 100.0
branch 44 44 100.0
condition n/a
subroutine 54 54 100.0
pod 0 30 0.0
total 362 392 92.3


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