File Coverage

blib/lib/Set/Array.pm
Criterion Covered Total %
statement 258 644 40.0
branch 107 402 26.6
condition 16 72 22.2
subroutine 37 58 63.7
pod 34 38 89.4
total 452 1214 37.2


line stmt bran cond sub pod time code
1             package Set::Array;
2              
3 2     2   47661 use strict;
  2         4  
  2         73  
4 2     2   1941 use attributes qw(reftype);
  2         4077  
  2         11  
5 2     2   2962 use subs qw(foreach pack push pop shift join rindex splice unpack unshift);
  2         52  
  2         12  
6              
7 2     2   2105 use Want;
  2         7603  
  2         213  
8 2     2   26 use Carp;
  2         4  
  2         155  
9 2     2   24864 use Try::Tiny;
  2         7737  
  2         8708  
10              
11             # Some not documented/implemented. Waiting for Want-0.06 to arrive.
12             use overload
13 2         1008 "==" => "is_equal",
14             "!=" => "not_equal",
15             "+" => "union",
16             "&" => "bag",
17             "*" => "intersection",
18             "-" => "difference",
19             "%" => "symmetric_difference",
20             "<<" => "push",
21             ">>" => "shift",
22             "<<=" => "unshift",
23             ">>=" => "pop",
24 2     2   3017 "fallback" => 1;
  2         1127  
25              
26             our $VERSION = '0.30';
27              
28             sub new{
29 23     23 1 7690 my($class,@array) = @_;
30 23 50 33     68 @array = @$class if !@array && ref($class);
31 23   33     128 return bless \@array, ref($class) || $class;
32             }
33              
34             # Turn array into a hash
35             sub as_hash{
36 6     6 1 22 my($self,$order,@arg) = @_;
37              
38 6 100       17 if (! defined $order) {
    100          
    100          
39 3         7 $order = 'even';
40             }
41             elsif (ref $order eq 'HASH') {
42 1         2 $order = $$order{'key_option'};
43             }
44             elsif ($order eq 'key_option') {
45 1         2 $order = $arg[0];
46             }
47              
48 6         9 $order = lc $order;
49              
50 6 50       23 if ($order =~ /^(?:odd|even)$/) {
51             }
52             else {
53 0         0 Carp::croak "Unrecognized option ($order) passed to 'as_hash()' method";
54             }
55              
56 6         7 my %hash;
57              
58 6 100       10 if($order eq 'odd') {
59 3         74 %hash = CORE::reverse(@$self);
60             }
61             else {
62 3         66 %hash = @$self;
63             }
64              
65 6 50       16 if(want('OBJECT')){ return $self } # This shouldn't happen
  0         0  
66              
67 6 100       272 return %hash if wantarray;
68 1         4 return \%hash;
69             }
70             *to_hash = \&as_hash;
71              
72             # Return element at specified index
73             sub at{
74 3     3 1 29075 my($self,$index) = @_;
75 3 50       16 if(want('OBJECT')){ return bless \${$self}[$index] }
  0         0  
  0         0  
76 3         188 return @$self[$index];
77             }
78              
79             # Delete (or undef) contents of array
80             sub clear{
81 2     2 1 5 my($self,$undef) = @_;
82 2 100       6 if($undef){ @{$self} = map{ undef } @{$self} }
  1         2  
  1         3  
  3         6  
  1         4  
83 1         2 else{ @{$self} = () }
  1         3  
84              
85 2 50       7 if(want('OBJECT')){ return $self }
  0         0  
86 2 50       82 if(wantarray){ return @$self }
  0         0  
87 2 50       8 if(defined wantarray){ return \@{$self} }
  2         3  
  2         8  
88             }
89              
90             # Remove all undef elements. It can be chained.
91              
92             sub compact{
93 2     2 1 7 my($self) = @_;
94              
95 2 100 66     7 if( (want('OBJECT')) || (!defined wantarray) ){
96 1         58 @$self = grep defined $_, @$self;
97 1         3 return $self;
98             }
99              
100 1         74 my @temp;
101 1 100       2 CORE::foreach(@{$self}){ CORE::push(@temp,$_) if defined $_ }
  1         4  
  6         15  
102 1 50       4 if(wantarray){ return @temp }
  0         0  
103 1 50       6 if(defined wantarray){ return \@temp }
  1         5  
104             }
105              
106             # Return the number of times the specified value appears within array
107             sub count{
108 4     4 1 443 my($self,$val) = @_;
109              
110 4         7 my $hits = 0;
111              
112             # Count undefined elements
113 4 50       17 unless(defined($val)){
114 0 0       0 foreach(@$self){ $hits++ unless $_ }
  0         0  
115 0 0       0 if(want('OBJECT')){ return bless \$hits }
  0         0  
116 0         0 return $hits;
117             }
118              
119 4         90 $hits = grep /^\Q$val\E$/, @$self;
120 4 50       14 if(want('OBJECT')){ return bless \$hits }
  0         0  
121 4         173 return $hits;
122             }
123              
124             # Pops and returns /the object/. I.e it can be chained.
125              
126             sub cpop{
127 4     4 1 15 my($self) = @_;
128 4         4 my $popped = CORE::pop(@$self);
129 4         8 return $self;
130             }
131              
132             # Shifts and returns /the object/. I.e it can be chained.
133              
134             sub cshift{
135 4     4 1 12 my($self) = @_;
136 4         5 my $shifted = CORE::shift @$self;
137 4         11 return $self;
138             }
139              
140             # Delete all instances of the specified value within the array. It can be chained.
141              
142             sub delete{
143 3     3 1 13 my($self,@vals) = @_;
144              
145 3 50       10 unless(defined($vals[0])){
146 0         0 Carp::croak "Undefined value passed to 'delete()' method";
147             }
148              
149 3         5 foreach my $val(@vals){
150 3         113 @$self = grep $_ !~ /^\Q$val\E$/, @$self;
151             }
152              
153 3 50       14 if(want('OBJECT')){ return $self }
  0         0  
154 3 50       152 if(wantarray){ return @$self }
  0         0  
155 3 100       13 if(defined wantarray){ return \@$self }
  2         18  
156             }
157              
158             # Deletes an element at a specified index, or range of indices
159             # I'm not sure I like the range behavior for this method and may change it
160             # (or remove it) in the future.
161             sub delete_at{
162 2     2 1 4 my($self,$start_index, $end_index) = @_;
163              
164 2 50       7 unless(defined($start_index)){
165 0         0 Carp::croak "No index passed to 'delete_at()' method";
166             }
167              
168 2 100       15 unless(defined($end_index)){ $end_index = 0 }
  1         4  
169 2 50 33     15 if( ($end_index eq 'end') || ($end_index == -1) ){ $end_index = $#$self }
  0         0  
170              
171 2         4 my $num = ($end_index - $start_index) + 1;
172              
173 2         4 CORE::splice(@{$self},$start_index,$num);
  2         5  
174              
175 2 50 33     9 if(want('OBJECT') || !(defined wantarray)){ return $self }
  0         0  
176 2 50       102 if(wantarray){ return @$self }
  0         0  
177 2 50       7 if(defined wantarray){ return \@{$self} }
  2         10  
  2         9  
178             }
179              
180             # Returns a list of duplicate items in the array. It can be chained.
181              
182             sub duplicates{
183 2     2 1 608 my($self) = @_;
184              
185 2         2 my(@dups,%count);
186              
187 2         6 CORE::foreach(@$self){
188 12         21 $count{$_}++;
189 12 100       27 if($count{$_} > 1){ CORE::push(@dups,$_) }
  4         8  
190             }
191              
192 2 50 33     8 if(want('OBJECT') || !(defined wantarray)){
193 0         0 @$self = @dups;
194 0         0 return $self;
195             }
196              
197 2 50       107 if(wantarray){ return @dups }
  2         11  
198 0 0       0 if(defined wantarray){ return \@dups }
  0         0  
199             }
200              
201             # Tests to see if value exists anywhere within array
202             sub exists{
203 2     2 1 671 my($self,$val) = @_;
204              
205             # Check specifically for undefined values
206 2 50       7 unless(defined($val)){
207 0 0       0 foreach(@$self){ unless($_){ return 1 } }
  0         0  
  0         0  
208 0         0 return 0;
209             }
210              
211 2 100       45 if(grep /^\Q$val\E$/, @$self){ return 1 }
  1         5  
212              
213 1         5 return 0;
214             }
215              
216             *contains = \&exists;
217              
218             # Fills the elements of the array. Does not create new elements
219             sub fill{
220 2     2 1 10 my($self,$val, $start, $length) = @_; # Start may also be a range
221 2 50       3 return unless(scalar(@{$self}) > 0); # Test for empty array
  2         8  
222              
223 2 100       5 unless(defined($start)){ $start = 0 }
  1         1  
224              
225 2 50       6 if($length){ $length += $start }
  0         0  
226 2         5 else{ $length = $#$self + 1}
227              
228 2 100       12 if($start =~ /^(\d+)\.\.(\d+)$/){
229 1         8 CORE::foreach($1..$2){ @{$self}[$_] = $val }
  2         3  
  2         6  
230 1         8 return $self;
231             }
232              
233 1         4 CORE::foreach(my $n=$start; $n<$length; $n++){ @{$self}[$n] = $val }
  3         5  
  3         19  
234              
235 1 50       4 if(want('OBJECT')){ return $self }
  0         0  
236 1 50       52 if(wantarray){ return @$self }
  0         0  
237 1 50       6 if(defined wantarray){ return \@{$self} }
  1         7  
  1         5  
238             }
239              
240             # Returns the first element of the array
241             sub first{
242 1     1 1 993 my($self) = @_;
243 1 50       6 if(want('OBJECT')){ return bless \@{$self}[0] }
  0         0  
  0         0  
244 1         62 return @{$self}[0];
  1         6  
245             }
246              
247             # Flattens any list references into a plain list
248             sub flatten{
249 1     1 1 2 my($self) = @_;
250              
251 1 50 33     4 if( (want('OBJECT')) || (!defined wantarray) ){
252 0         0 for(my $n=0; $n<=$#$self; $n++){
253 0 0       0 if( ref($$self[$n]) eq 'ARRAY' ){
254 0         0 CORE::splice(@$self,$n,1,@{$$self[$n]});
  0         0  
255 0         0 $n--;
256 0         0 next;
257             }
258 0 0       0 if( ref($$self[$n]) eq 'HASH' ){
259 0         0 CORE::splice(@$self,$n,1,%{$$self[$n]});
  0         0  
260 0         0 --$n;
261 0         0 next;
262             }
263             }
264 0         0 return $self
265             }
266              
267 1         54 my @temp = @$self;
268 1         6 for(my $n=0; $n<=$#temp; $n++){
269 8 100       17 if( ref($temp[$n]) eq 'ARRAY' ){
270 2         4 CORE::splice(@temp,$n,1,@{$temp[$n]});
  2         8  
271 2         2 $n--;
272 2         6 next;
273             }
274 6 50       18 if( ref($temp[$n]) eq 'HASH' ){
275 0         0 CORE::splice(@temp,$n,1,%{$temp[$n]});
  0         0  
276 0         0 --$n;
277 0         0 next;
278             }
279             }
280 1 50       11 if(wantarray){ return @temp }
  1         6  
281 0 0       0 if(defined wantarray){ return \@temp }
  0         0  
282             }
283              
284             # Loop mechanism
285             sub foreach{
286 1     1   645 my($self,$coderef) = @_;
287              
288 1 50       7 unless(ref($coderef) eq 'CODE'){
289 0         0 Carp::croak "Invalid code reference passed to 'foreach' method";
290             }
291              
292 1         3 CORE::foreach (@$self){ &$coderef }
  5         18  
293              
294 1 50       6 if(want('OBJECT')){ return $self }
  0         0  
295 1 50       48 if(wantarray){ return @$self }
  0         0  
296 1 50       6 if(defined wantarray){ return \@{$self} }
  1         2  
  1         5  
297             }
298              
299             # Append or prepend a string to each element of the array
300             sub impose{
301 0     0 1 0 my($self,$placement,$string) = @_;
302              
303             # Set defaults
304 0 0       0 unless($placement =~ /\bappend\b|\bprepend\b/i){
305 0         0 $string = $placement;
306 0         0 $placement = 'append';
307             }
308              
309 0 0       0 unless(CORE::defined($string)){
310 0         0 Carp::croak "No string supplied to 'impose()' method";
311             }
312              
313 0 0 0     0 if(want('OBJECT') or !(defined wantarray)){
314 0 0       0 if($placement =~ /append/){ foreach(@$self){ $_ = $_ . $string } }
  0         0  
  0         0  
315 0 0       0 if($placement =~ /prepend/){ foreach(@$self){ $_ = $string . $_ } }
  0         0  
  0         0  
316 0         0 return $self;
317             }
318              
319 0         0 my @copy = @$self;
320 0 0       0 if($placement =~ /append/){ foreach(@copy){ $_ = $_ . $string } }
  0         0  
  0         0  
321 0 0       0 if($placement =~ /prepend/){ foreach(@copy){ $_ = $string . $_ } }
  0         0  
  0         0  
322              
323 0 0       0 if(wantarray){ return @copy }
  0         0  
324 0 0       0 if(defined wantarray){ return \@copy }
  0         0  
325             }
326              
327             # Returns the index of the first occurrence within the array
328             # of the specified value
329             sub index{
330 1     1 1 228 my($self,$val) = @_;
331              
332             # Test for undefined value
333 1 50       3 unless(defined($val)){
334 0         0 for(my $n=0; $n<=$#$self; $n++){
335 0 0       0 unless($self->[$n]){
336 0 0       0 if(want('OBJECT')){ return bless \$n }
  0         0  
337 0 0       0 if(defined wantarray){ return $n }
  0         0  
338             }
339             }
340             }
341              
342 1         4 for(my $n=0; $n<=$#$self; $n++){
343 1 50       3 next unless defined $self->[$n];
344 1 50       12 if( $self->[$n] =~ /^\Q$val\E$/ ){
345 1 50       51 if(want('OBJECT')){ return bless \$n }
  0         0  
346 1 50       48 if(defined wantarray){ return $n }
  1         3  
347             }
348             }
349 0         0 return undef;
350             }
351              
352             # Given an index, or range of indices, returns the value at that index
353             # (or a list of values for a range).
354             sub indices{
355 1     1 1 63 my($self,@indices) = @_;
356 1         2 my @iArray;
357              
358 1 50       36 unless(defined($indices[0])){
359 0         0 Carp::croak "No index/indices passed to 'indices' (aka 'get') method";
360             }
361              
362 1         4 CORE::foreach(@indices){
363 1 50       9 if($_ =~ /(\d+)\.\.(\d+)/){ for($1..$2){
  1         6  
364 3         4 CORE::push(@iArray,@{$self}[$_]) };
  3         9  
365 1         3 next;
366             }
367 0 0       0 if(@{$self}[$_]){ CORE::push(@iArray,@{$self}[$_]) }
  0         0  
  0         0  
  0         0  
368 0         0 else{ CORE::push(@iArray,undef) }
369             }
370              
371 1 50       12 if(scalar(@iArray) == 1){
372 0 0       0 if(want('OBJECT')){ return bless \$iArray[0] }
  0         0  
373 0         0 return $iArray[0];
374             }
375              
376 1 50       5 if(want('OBJECT')){ return bless \@iArray }
  1         55  
377 0 0       0 if(wantarray){ return @iArray }
  0         0  
378 0 0       0 if(defined wantarray){ return \@iArray }
  0         0  
379             }
380              
381             # Alias for 'indices()'
382             *get = \&indices;
383              
384             # Tests to see if array contains any elements
385             sub is_empty{
386 0     0 1 0 my($self) = @_;
387 0 0       0 if( (scalar @{$self}) > 0){ return 0 }
  0         0  
  0         0  
388 0         0 return 1;
389             }
390              
391             # Set a specific index to a specific value
392             sub set{
393 0     0 1 0 my($self,$index,$val) = @_;
394              
395 0 0 0     0 unless(defined($index) && $val){
396 0         0 Carp::croak "No index or value passed to 'set()' method";
397             }
398              
399 0 0       0 if(want('OBJECT')){
400 0         0 $self->[$index] = $val;
401 0         0 return $self;
402             }
403              
404 0         0 my @copy = @$self;
405 0         0 $copy[$index] = $val;
406              
407 0 0       0 if(wantarray){ return @copy }
  0         0  
408 0 0       0 if(defined wantarray){ return \@copy }
  0         0  
409             }
410              
411             # Joins the contents of the list with the specified string
412             sub join{
413 5     5   21 my($self,$s) = @_;
414              
415 5 50       12 $s = ',' unless $s;
416              
417 5         7 my $string;
418              
419 5 50       15 if(want('OBJECT')){
420 5         602 $string = CORE::join($s,@$self);
421 5         24 return bless \$string;
422             }
423              
424 0         0 $string = CORE::join($s,@$self);
425 0         0 return $string;
426             }
427              
428             # Returns the last element of the array
429             sub last{
430 0     0 1 0 my($self) = @_;
431 0 0       0 if(want('OBJECT')){ return bless \@{$self}[-1] }
  0         0  
  0         0  
432 0         0 return @$self[-1];
433             }
434              
435             # Returns the number of elements within the array
436             sub length{
437 5     5 1 16368 my($self) = @_;
438 5         9 my $length = scalar(@$self);
439 5 50       18 if(want('OBJECT')){ return bless \$length }
  0         0  
440 5         244 return $length;
441             }
442              
443             # Returns the maximum numerical value in the array
444             sub max{
445 0     0 1 0 my($self) = @_;
446 0         0 my $max;
447              
448 2     2   12910 no warnings 'uninitialized';
  2         6  
  2         2471  
449 0 0       0 CORE::foreach(@{$self}){ $max = $_ if $_ > $max }
  0         0  
  0         0  
450              
451 0 0       0 if(want('OBJECT')){ return bless \$max }
  0         0  
452 0         0 return $max;
453             }
454              
455             sub pack{
456 0     0   0 my($self,$template) = @_;
457              
458 0 0       0 Carp::croak "No template provided to 'pack()' method" unless $template;
459              
460 0 0 0     0 if(want('OBJECT') || !(defined wantarray)){
461 0         0 $self->[0] = CORE::pack($template, @$self);
462 0         0 $#$self = 0;
463 0         0 return $self;
464             }
465              
466 0         0 return CORE::pack($template,@$self);
467             }
468              
469             # Pops and returns the last element off the array
470             sub pop{
471 0     0   0 my($self) = @_;
472 0         0 my $popped = CORE::pop(@$self);
473 0 0       0 if(want('OBJECT')){ return bless \$popped }
  0         0  
474 0         0 return $popped;
475             }
476              
477             # Prints the contents of the array as a flat list. Optional newline
478             sub print{
479 6     6 1 16 my($self,$nl) = @_;
480              
481 6 100       42 if(reftype($self) eq 'ARRAY'){
    50          
482 1 50       5 if(wantarray){ return @$self }
  1         6  
483 0 0       0 if(defined wantarray){ return \@{$self} }
  0         0  
  0         0  
484 0         0 CORE::print @$self;
485 0 0       0 if($nl){ CORE::print "\n" }
  0         0  
486             }
487             elsif(reftype($self) eq 'SCALAR'){
488 5 50       12 if(defined wantarray){ return $$self }
  5         19  
489 0         0 CORE::print $$self;
490 0 0       0 if($nl){ CORE::print "\n" }
  0         0  
491             }
492             else{
493 0         0 CORE::print @$self;
494 0 0       0 if($nl){ CORE::print "\n" }
  0         0  
495             }
496 0         0 return $self;
497             }
498              
499             # Pushes an element onto the end of the array
500             sub push{
501 0     0   0 my($self,@list) = @_;
502              
503 0         0 CORE::push(@{$self},@list);
  0         0  
504              
505 0 0       0 if(want('OBJECT')){ return $self }
  0         0  
506 0 0       0 if(wantarray){ return @$self }
  0         0  
507 0 0       0 if(defined wantarray){ return \@{$self} };
  0         0  
  0         0  
508             }
509              
510             # Randomizes the order of the contents of the array
511             # Taken from "The Perl Cookbook"
512             sub randomize{
513 0     0 1 0 my($self) = @_;
514 0         0 my($i,$ref,@temp);
515              
516 0 0 0     0 unless( (want('OBJECT')) || (!defined wantarray) ){
517 0         0 @temp = @{$self};
  0         0  
518 0         0 $ref = \@temp;
519             }
520 0         0 else{ $ref = $self }
521              
522 0         0 for($i = @$ref; --$i; ){
523 0         0 my $j = int rand ($i+1);
524 0 0       0 next if $i == $j;
525 0         0 @$ref[$i,$j] = @$ref[$j,$i];
526             }
527              
528 0 0       0 if(want('OBJECT')){ return $self }
  0         0  
529 0 0       0 if(wantarray){ return @temp }
  0         0  
530 0 0       0 if(defined wantarray){ return \@temp }
  0         0  
531             }
532              
533             # Reverses the contents of the array
534             sub reverse{
535 1     1 1 3 my($self) = @_;
536              
537 1 50 33     3 if( (want('OBJECT')) || (!defined wantarray) ){
538 0         0 @$self = CORE::reverse @$self;
539 0         0 return $self;
540             }
541              
542 1         43 my @temp = CORE::reverse @$self;
543 1 50       3 if(wantarray){ return @temp }
  1         6  
544 0 0       0 if(defined wantarray){ return \@temp }
  0         0  
545             }
546              
547             # Same as index, except that it returns the position of the
548             # last occurrence, instead of the first.
549             sub rindex{
550 2     2   490 my($self,$val) = @_;
551              
552             # Test for undefined value
553 2 50       7 unless(defined($val)){
554 0         0 for(my $n = $#$self; $n >= 0; $n--){
555 0 0       0 unless($self->[$n]){
556 0 0       0 if(want('OBJECT')){ return bless \$n }
  0         0  
557 0 0       0 if(defined wantarray){ return $n }
  0         0  
558             }
559             }
560             }
561              
562 2         7 for(my $n = $#$self; $n >= 0; $n--){
563 5 50       20 next unless defined $self->[$n];
564 5 100       45 if( $self->[$n] =~ /^\Q$val\E$/ ){
565 1 50       4 if(want('OBJECT')){ return bless \$n }
  0         0  
566 1 50       69 if(defined wantarray){ return $n }
  1         5  
567             }
568             }
569 1         4 return undef;
570              
571             }
572              
573             # Moves the last element of the array to the front, or vice-versa
574             sub rotate{
575 0     0 1 0 my($self,$dir) = @_;
576              
577 0 0 0     0 if( (want('OBJECT')) || (!defined wantarray) ){
578 0 0 0     0 unless(defined($dir) && $dir eq 'ftol'){
579 0         0 CORE::unshift(@$self, CORE::pop(@$self));
580 0         0 return $self;
581             }
582 0         0 CORE::push(@$self,CORE::shift(@$self));
583 0         0 return $self;
584             }
585              
586 0         0 my @temp = @$self;
587 0 0 0     0 unless(defined($dir) && $dir eq 'ftol'){
588 0         0 CORE::unshift(@temp, CORE::pop(@temp));
589 0 0       0 if(wantarray){ return @temp }
  0         0  
590 0 0       0 if(defined wantarray){ return \@temp }
  0         0  
591             }
592 0         0 CORE::push(@temp,CORE::shift(@temp));
593 0 0       0 if(wantarray){ return @temp }
  0         0  
594 0 0       0 if(defined wantarray){ return \@temp }
  0         0  
595             }
596              
597             # Shifts and returns the first element off the array
598             sub shift{
599 0     0   0 my($self) = @_;
600 0         0 my $shifted = CORE::shift @$self;
601 0 0       0 if(want('OBJECT')){ return bless \$shifted }
  0         0  
602 0         0 return $shifted;
603             }
604              
605             # Sorts the array alphabetically.
606             sub sort{
607 0     0 1 0 my($self,$coderef) = @_;
608              
609 0 0       0 if($coderef){
610              
611             # Complements of Sean McAfee
612 0         0 my $caller = caller();
613 0         0 local(*a,*b) = do{
614 2     2   13 no strict 'refs';
  2         4  
  2         445  
615 0         0 (*{"${caller}::a"},*{"${caller}::b"});
  0         0  
  0         0  
616             };
617              
618 0 0 0     0 if( (want('OBJECT')) || (!defined wantarray) ){
619 0         0 @$self = CORE::sort $coderef @$self;
620 0         0 return $self;
621             }
622              
623 0         0 my @sorted = CORE::sort $coderef @$self;
624 0 0       0 if(wantarray){ return @sorted }
  0         0  
625 0 0       0 if(defined wantarray){ return \@sorted }
  0         0  
626             }
627             else{
628 0 0 0     0 if( (want('OBJECT')) || (!defined wantarray) ){
629 0         0 @$self = CORE::sort @$self;
630 0         0 return $self;
631             }
632 0         0 my @sorted = CORE::sort @$self;
633 0 0       0 if(wantarray){ return @sorted }
  0         0  
634 0 0       0 if(defined wantarray){ return \@sorted }
  0         0  
635             }
636             }
637              
638             # Splices a value, or range of values, from the array
639             sub splice{
640 0     0   0 my($self,$offset,$length,@list) = @_;
641              
642 2     2   26 no warnings 'uninitialized';
  2         4  
  2         3577  
643              
644 0         0 my @deleted;
645 0 0       0 unless(defined($offset)){
646 0         0 @deleted = CORE::splice(@$self);
647 0 0       0 if(want('OBJECT')){ return $self }
  0         0  
648 0 0       0 if(wantarray){ return @deleted }
  0         0  
649 0 0       0 if(defined wantarray){ return \@deleted }
  0         0  
650             }
651 0 0       0 unless(defined($length)){
652 0         0 @deleted = CORE::splice(@$self,$offset);
653 0 0       0 if(want('OBJECT')){ return $self }
  0         0  
654 0 0       0 if(wantarray){ return @deleted }
  0         0  
655 0 0       0 if(defined wantarray){ return \@deleted }
  0         0  
656             }
657 0 0       0 unless(defined($list[0])){
658 0         0 @deleted = CORE::splice(@$self,$offset,$length);
659 0 0       0 if(want('OBJECT')){ return $self }
  0         0  
660 0 0       0 if(wantarray){ return @deleted }
  0         0  
661 0 0       0 if(defined wantarray){ return \@deleted }
  0         0  
662             }
663              
664 0         0 @deleted = CORE::splice(@$self,$offset,$length,@list);
665 0 0       0 if(want('OBJECT')){ return $self }
  0         0  
666 0 0       0 if(wantarray){ return @deleted }
  0         0  
667 0 0       0 if(defined wantarray){ return \@deleted }
  0         0  
668             }
669              
670             # Returns a list of unique items in the array. It can be chained.
671              
672             sub unique{
673 3     3 1 6 my($self) = @_;
674              
675 3         6 my %item;
676              
677 3         9 CORE::foreach(@$self){ $item{$_}++ }
  18         32  
678              
679 3 100 66     10 if(want('OBJECT') || !(defined wantarray)){
680 1         50 @$self = keys %item;
681 1         6 return $self;
682             }
683              
684 2         92 my @temp = keys %item;
685              
686 2 100       8 if(wantarray){ return @temp }
  1         7  
687 1 50       24 if(defined wantarray){ return \@temp }
  1         4  
688             }
689              
690             # Unshifts a value to the front of the array
691             sub unshift{
692 0     0   0 my($self,@list) = @_;
693 0         0 CORE::unshift(@$self,@list);
694              
695 0 0       0 if(want('OBJECT')){ return $self }
  0         0  
696 0 0       0 if(wantarray){ return @$self }
  0         0  
697 0 0       0 if(defined wantarray){ return \@{$self} };
  0         0  
  0         0  
698             }
699              
700             #### OVERLOADED OPERATOR METHODS ####
701              
702             # Really just a 'push', but needs to handle ops
703             sub append{
704 0     0 0 0 my($op1, $op2, $reversed) = @_;
705 0 0       0 ($op2,$op1) = ($op1,$op2) if $reversed;
706              
707 0         0 CORE::push(@{$op1},@{$op2});
  0         0  
  0         0  
708              
709 0 0       0 if(want('OBJECT')){ return $op1 }
  0         0  
710 0 0       0 return @$op1 if wantarray;
711 0 0       0 return \@{$op1} if defined wantarray;
  0         0  
712             }
713              
714             # A union that includes non-unique values (i.e. everything)
715             sub bag{
716 0     0 1 0 my($op1, $op2, $reversed) = @_;
717 0 0       0 ($op2,$op1) = ($op1,$op2) if $reversed;
718              
719 0 0 0     0 if(want('OBJECT') || !(defined wantarray)){
720 0         0 CORE::push(@$op1,@$op2);
721 0         0 return $op1;
722             }
723 0         0 my @copy = (@$op1,@$op2);
724 0 0       0 return @copy if wantarray;
725 0 0       0 return \@copy if defined wantarray;
726             }
727              
728             # Needs work
729             sub complement{
730 0     0 0 0 my($op1, $op2, $reversed) = @_;
731 0 0       0 ($op2,$op1) = ($op1,$op2) if $reversed;
732              
733 0         0 my(%item1,%item2,@comp);
734 0         0 CORE::foreach(@$op1){ $item1{$_}++ }
  0         0  
735 0         0 CORE::foreach(@$op2){ $item2{$_}++ }
  0         0  
736              
737 0         0 CORE::foreach(keys %item2){
738 0 0       0 if($item1{$_}){ next }
  0         0  
739 0         0 CORE::push(@comp,$_);
740             }
741              
742 0 0       0 if(want('OBJECT')){ return bless \@comp }
  0         0  
743 0 0       0 if(wantarray){ return @comp }
  0         0  
744 0 0       0 if(defined wantarray){ return \@comp }
  0         0  
745             }
746              
747             # Returns elements in left set that are not in the right set
748             sub difference{
749 1     1 1 7 my($op1, $op2, $reversed) = @_;
750 1 50       3 ($op2,$op1) = ($op1,$op2) if $reversed;
751              
752 1         2 my(%item1,%item2,@diff);
753 1         4 CORE::foreach(@$op1){ $item1{$_}=$_ }
  8         92  
754 1         10 CORE::foreach(@$op2){ $item2{$_}=$_ }
  3         16  
755              
756 1         10 CORE::foreach(keys %item1){
757 8 100       17 if(exists $item2{$_}){ next }
  3         5  
758 5         9 CORE::push(@diff,$item1{$_});
759             }
760              
761             try
762             {
763 1 50 33 1   25 if (want('OBJECT') || ! defined wantarray)
764             {
765 1         61 @$op1 = @diff;
766 1         4 return $op1;
767             }
768 1         11 };
769              
770 1 50       16 if(wantarray){ return @diff }
  1         15  
771 0 0       0 if(defined wantarray){ return \@diff }
  0         0  
772             }
773              
774             # Returns the elements common to both arrays
775             sub intersection{
776 2     2 1 11 my($op1, $op2, $reversed) = @_;
777 2 50       7 ($op2,$op1) = ($op1,$op2) if $reversed;
778 2         4 my($result) = [];
779              
780 2         57 my($i1, $i2);
781 0         0 my(%seen);
782              
783 2         8 CORE::foreach $i1 (0 .. $#$op1){
784 10         27 CORE::foreach $i2 (0 .. $#$op2){
785             # If we have matched this value in @$op2 before,
786             # do not match it in the same place again in @$op1.
787              
788 52 100 100     157 next if (defined $seen{$$op2[$i2]} && ($seen{$$op2[$i2]} eq $i1) );
789              
790 48 100       110 if ($$op1[$i1] eq $$op2[$i2]){
791 6         11 CORE::push @$result, $$op1[$i1];
792              
793 6         11 $seen{$$op2[$i2]} = $i1;
794             }
795             }
796             }
797              
798 2 50 33     9 if(want('OBJECT') || !(defined wantarray)){
799 0         0 return $result;
800             }
801              
802 2 50       123 if(wantarray){ return @$result }
  2         20  
803 0 0         if(defined wantarray){ return $result }
  0            
804             }
805              
806             # Tests to see if arrays are equal (regardless of order)
807             sub is_equal{
808 0     0 1   my($op1, $op2, $reversed) = @_;
809 0 0         ($op2,$op1) = ($op1,$op2) if $reversed;
810              
811 0           my(%count1, %count2);
812              
813 0 0         if(scalar(@$op1) != scalar(@$op2)){ return 0 }
  0            
814              
815 0           CORE::foreach(@$op1){ $count1{$_}++ }
  0            
816 0           CORE::foreach(@$op2){ $count2{$_}++ }
  0            
817              
818 0           CORE::foreach my $key(keys %count1){
819 0 0         return 0 unless CORE::defined($count1{$key});
820 0 0         return 0 unless CORE::defined($count2{$key});
821 0 0         if($count1{$key} ne $count2{$key}){ return 0 }
  0            
822             }
823 0           return 1;
824             }
825              
826             # Tests to see if arrays are not equal (order ignored)
827             sub not_equal{
828 0     0 1   my($op1, $op2, $reversed) = @_;
829 0 0         ($op2,$op1) = ($op1,$op2) if $reversed;
830              
831 0           my(%count1, %count2);
832              
833 0 0         if(scalar(@$op1) != scalar(@$op2)){ return 1 }
  0            
834              
835 0           CORE::foreach(@$op1){ $count1{$_}++ }
  0            
836 0           CORE::foreach(@$op2){ $count2{$_}++ }
  0            
837              
838 0           CORE::foreach my $key(keys %count1){
839 0 0         return 1 unless CORE::defined($count1{$key});
840 0 0         return 1 unless CORE::defined($count2{$key});
841 0 0         if($count1{$key} ne $count2{$key}){ return 1 }
  0            
842             }
843 0           return 0;
844             }
845              
846             # Returns elements in one set or the other, but not both
847             sub symmetric_difference{
848 0     0 0   my($op1, $op2, $reversed) = @_;
849 0 0         ($op2,$op1) = ($op1,$op2) if $reversed;
850              
851 0           my(%count1,%count2,%count3,@symdiff);
852 0           @count1{@$op1} = (1) x @$op1;
853 0           @count2{@$op2} = (1) x @$op2;
854              
855 0           CORE::foreach(CORE::keys %count1,CORE::keys %count2){ $count3{$_}++ }
  0            
856              
857 0 0 0       if(want('OBJECT') || !(defined wantarray)){
858 0           @$op1 = CORE::grep{$count3{$_} == 1} CORE::keys %count3;
  0            
859 0           return $op1;
860             }
861              
862 0           @symdiff = CORE::grep{$count3{$_} == 1} CORE::keys %count3;
  0            
863 0 0         if(wantarray){ return @symdiff }
  0            
864 0 0         if(defined wantarray){ return \@symdiff }
  0            
865             }
866              
867             *sym_diff = \&symmetric_difference;
868              
869             # Returns the union of two arrays, non-unique values excluded
870             sub union{
871 0     0 0   my($op1, $op2, $reversed) = @_;
872 0 0         ($op2,$op1) = ($op1,$op2) if $reversed;
873              
874 0           my %union;
875 0           CORE::foreach(@$op1, @$op2){ $union{$_}++ }
  0            
876              
877 0 0 0       if(want('OBJECT') || !(defined wantarray)){
878 0           @$op1 = CORE::keys %union;
879 0           return $op1;
880             }
881              
882 0           my @union = CORE::keys %union;
883              
884 0 0         if(wantarray){ return @union }
  0            
885 0 0         if(defined wantarray){ return \@union }
  0            
886             }
887             1;
888             __END__