File Coverage

lib/Ruby/Collections/Array.pm
Criterion Covered Total %
statement 1122 1231 91.1
branch 358 574 62.3
condition 51 99 51.5
subroutine 122 124 98.3
pod 101 106 95.2
total 1754 2134 82.1


line stmt bran cond sub pod time code
1             package Ruby::Collections::Array;
2 3     3   5434 use Tie::Array;
  3         4130  
  3         137  
3             our @ISA = 'Tie::StdArray';
4 3     3   18 use strict;
  3         6  
  3         100  
5 3     3   84 use v5.10;
  3         10  
  3         127  
6 3     3   16 use Scalar::Util qw(looks_like_number reftype);
  3         5  
  3         188  
7 3     3   3012 use Math::Combinatorics;
  3         47848  
  3         248  
8 3     3   3078 use Set::CrossProduct;
  3         9929  
  3         132  
9 3     3   28 use FindBin;
  3         6  
  3         179  
10 3     3   18 use lib "$FindBin::Bin/../../../lib";
  3         5  
  3         28  
11 3     3   1235 use Ruby::Collections;
  3         8  
  3         499  
12             use overload (
13 3         56 '+' => \&add,
14             '-' => \&minus,
15             '*' => \&multiply,
16             '&' => \&intersection,
17             '|' => \&union,
18             '<<' => \&double_left_arrows,
19             '==' => \&eql,
20             'eq' => \&eql,
21             '!=' => \¬_eql,
22             'ne' => \¬_eql,
23             '""' => \&to_s
24 3     3   17 );
  3         6  
25              
26             =item add()
27             Append other ARRAY to itself.
28             =cut
29              
30             sub add {
31 3     3 1 7 my ( $self, $other_ary ) = @_;
32 3 50       9 ref($self) eq __PACKAGE__ or die;
33              
34 3         11 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
35 3         19 @new_ary = @$self;
36 3         39 push( @new_ary, @{$other_ary} );
  3         12  
37              
38 3         21 return $new_ary;
39             }
40              
41             =item minus()
42             Remove all elements which other ARRAY contains from itself.
43             =cut
44              
45             sub minus {
46 2     2 1 4 my ( $self, $other_ary ) = @_;
47 2 50       12 ref($self) eq __PACKAGE__ or die;
48              
49 2         10 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
50 2         13 @new_ary = @{$self};
  2         8  
51 2         32 for my $item ( @{$other_ary} ) {
  2         4  
52 9         27 $new_ary->delete($item);
53             }
54              
55 2         12 return $new_ary;
56             }
57              
58             =item multiply()
59             Duplicate self by a number of times or join all elements by a string.
60             =cut
61              
62             sub multiply {
63 3     3 1 6 my ( $self, $sep_or_n ) = @_;
64 3 50       14 ref($self) eq __PACKAGE__ or die;
65              
66 3         12 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
67 3 100       25 if ( looks_like_number $sep_or_n ) {
68 2 100       20 die 'ArgumentError: negative argument' if ( $sep_or_n < 0 );
69              
70 1         5 for ( my $i = 0 ; $i < $sep_or_n ; $i++ ) {
71 2         49 push( @new_ary, @{$self} );
  2         9  
72             }
73 1         13 return $new_ary;
74             }
75             else {
76 1         2 return join( $sep_or_n, @{$self} );
  1         9  
77             }
78             }
79              
80             =item intersection()
81             Generate an intersection set between self and other ARRAY.
82             =cut
83              
84             sub intersection {
85 1     1 1 3 my ( $self, $other ) = @_;
86 1 50       4 ref($self) eq __PACKAGE__ or die;
87              
88 1         4 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
89 1         6 foreach my $item ( @{$self} ) {
  1         2  
90 5 100 33     14 if ( ( not $new_ary->include($item) )
      66        
91             && $self->include($item)
92             && ra($other)->include($item) )
93             {
94 2         6 $new_ary->push($item);
95             }
96             }
97              
98 1         6 return $new_ary;
99             }
100              
101             =item has_all()
102             Check if all elements are defined.
103             When block given, check if all results returned by block are true.
104             =cut
105              
106             sub has_all {
107 4     4 1 8 my ( $self, $block ) = @_;
108 4 50       10 ref($self) eq __PACKAGE__ or die;
109              
110 4         6 for my $item ( @{$self} ) {
  4         9  
111 5 100       22 if ( defined $block ) {
112 4 100       10 return 0 if ( not $block->($item) );
113             }
114             else {
115 1 50       7 return 0 if ( not defined $item );
116             }
117             }
118              
119 2         18 return 1;
120             }
121              
122             =item has_any()
123             Check if any element is defined.
124             When block given, check if any result returned by block are true.
125             =cut
126              
127             sub has_any {
128 12     12 1 28 my ( $self, $block ) = @_;
129 12 50       43 ref($self) eq __PACKAGE__ or die;
130              
131 12         16 for my $item ( @{$self} ) {
  12         28  
132 18 100       55 if ( defined $block ) {
133 11 100       22 return 1 if ( $block->($item) );
134             }
135             else {
136 7 100       54 return 1 if ( defined $item );
137             }
138             }
139              
140 5         24 return 0;
141             }
142              
143             =item assoc()
144             Find the first sub array which contains target object as the first element.
145             =cut
146              
147             sub assoc {
148 2     2 1 4 my ( $self, $target ) = @_;
149 2 50       17 ref($self) eq __PACKAGE__ or die;
150              
151 2         2 for my $item ( @{$self} ) {
  2         6  
152 7 100       25 if ( reftype($item) eq 'ARRAY' ) {
153 1         2 my @sub_array = @{$item};
  1         4  
154 1 50       4 if ( p_obj( $sub_array[0] ) eq p_obj($target) ) {
155 1         4 my $ret = tie my @ret, 'Ruby::Collections::Array';
156 1         6 @ret = @sub_array;
157 1         16 return $ret;
158             }
159             }
160             }
161              
162 1         9 return undef;
163             }
164              
165             =item at()
166             Return the element of certain position.
167             Return undef if element is not found.
168             =cut
169              
170             sub at {
171 305     305 1 441 my ( $self, $index ) = @_;
172 305 50       707 ref($self) eq __PACKAGE__ or die;
173              
174 305         340 return @{$self}[$index];
  305         1829  
175             }
176              
177             =item bsearch()
178             Find the element by certain condition.
179             Return undef if element is not found.
180             Note: The real binary search is not implemented yet.
181             =cut
182              
183             sub bsearch {
184 2     2 1 4 my ( $self, $block ) = @_;
185 2 50       9 ref($self) eq __PACKAGE__ or die;
186              
187 2         3 for my $item ( @{$self} ) {
  2         5  
188 8 100       51 if ( $block->($item) ) {
189 1         169 return $item;
190             }
191             }
192              
193 1         10 return undef;
194             }
195              
196             =item chunk()
197             Chunk consecutive elements which is under certain condition
198             into [ condition, [ elements... ] ] array.
199            
200             ra( 1, 3, 2, 4, 5, 6 )->chunk( sub { $_[0] % 2 } )
201             # return [ [ 1, [ 1, 3 ] ], [ 0, [ 2, 4 ] ], [ 1, [5] ], [ 0, [6] ] ]
202             =cut
203              
204             sub chunk {
205 1     1 1 4 my ( $self, $block ) = @_;
206 1 50       6 ref($self) eq __PACKAGE__ or die;
207              
208 1         6 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
209 1         6 my $prev = undef;
210 1         4 my $chunk = tie my @chunk, 'Ruby::Collections::Array';
211 1         7 for ( my $i = 0 ; $i < scalar( @{$self} ) ; $i++ ) {
  7         27  
212 6         10 my $key = $block->( @{$self}[$i] );
  6         25  
213 6 100       44 if ( p_obj($key) eq p_obj($prev) ) {
214 2         6 $chunk->push( @{$self}[$i] );
  2         10  
215             }
216             else {
217 4 100       14 if ( $i != 0 ) {
218 3         18 my $sub_ary = tie my @sub_ary, 'Ruby::Collections::Array';
219 3         30 $sub_ary->push( $prev, $chunk );
220 3         11 $new_ary->push($sub_ary);
221             }
222 4         10 $prev = $key;
223 4         27 $chunk = tie my @chunk, 'Ruby::Collections::Array';
224 4         33 $chunk->push( @{$self}[$i] );
  4         16  
225             }
226             }
227 1 50       10 if ( $chunk->has_any ) {
228 1         8 my $sub_ary = tie my @sub_ary, 'Ruby::Collections::Array';
229 1         13 $sub_ary->push( $prev, $chunk );
230 1         6 $new_ary->push($sub_ary);
231             }
232              
233 1         33 return $new_ary;
234             }
235              
236             =item clear()
237             Clear all elements.
238             =cut
239              
240             sub clear {
241 78     78 1 125 my ($self) = @_;
242 78 50       241 ref($self) eq __PACKAGE__ or die;
243              
244 78         104 @{$self} = ();
  78         191  
245              
246 78         242 return $self;
247             }
248              
249             =item combination()
250             Generate all combinations of certain length n of all elements.
251            
252             ra( 1, 2, 3, 4 )->combination(2) # return [[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]
253             ra( 1, 2, 3 )->combination( 3, sub {
254             print $_[0]->to_s;
255             } )
256             # print "[3, 1, 2]"
257             =cut
258              
259             sub combination {
260 3     3 1 7 my ( $self, $n, $block ) = @_;
261 3 50       12 ref($self) eq __PACKAGE__ or die;
262 3         32 my $combinat =
263 3         7 Math::Combinatorics->new( count => $n, data => [ @{$self} ] );
264              
265 3         146 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
266 3 50       19 if ( $n < 0 ) {
267 0 0       0 if ( defined $block ) {
268 0         0 return $self;
269             }
270             else {
271 0         0 return $new_ary;
272             }
273             }
274 3 50       8 if ( $n == 0 ) {
275 0 0       0 if ( defined $block ) {
276 0         0 $block->( tie my @empty_ary, 'Ruby::Collections::Array' );
277 0         0 return $self;
278             }
279             else {
280 0         0 push( @new_ary, tie my @empty_ary, 'Ruby::Collections::Array' );
281 0         0 return $new_ary;
282             }
283             }
284              
285 3         14 while ( my @combo = $combinat->next_combination ) {
286 8         564 my $c = tie my @c, 'Ruby::Collections::Array';
287 8         48 @c = @combo;
288 8 100       109 if ( defined $block ) {
289 1         3 $block->($c);
290             }
291             else {
292 7         17 push( @new_ary, $c );
293             }
294             }
295              
296 3 100       137 if ( defined $block ) {
297 1         9 return $self;
298             }
299             else {
300 2         35 return $new_ary;
301             }
302             }
303              
304             =item compact()
305             Remove all undef elements and store the result in a Ruby::Collections::Array.
306            
307             ra( 1, undef, 3, undef, 5 )->compact # return [ 1, 3, 5 ]
308             =cut
309              
310             sub compact {
311 1     1 1 2 my ($self) = @_;
312 1 50       5 ref($self) eq __PACKAGE__ or die;
313              
314 1         4 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
315 1         6 for my $item ( @{$self} ) {
  1         2  
316 5 100       20 if ( defined $item ) {
317 3         6 push( @new_ary, $item );
318             }
319             }
320              
321 1         9 return $new_ary;
322             }
323              
324             =item compactEx()
325             Remove all undef elements in self.
326            
327             ra( 1, undef, 3, undef, 5 )->compact # return [ 1, 3, 5 ]
328             =cut
329              
330             sub compactEx {
331 1     1 1 6 my ($self) = @_;
332 1 50       5 ref($self) eq __PACKAGE__ or die;
333              
334 1         2 my @new_ary;
335 1         3 for my $item ( @{$self} ) {
  1         5  
336 5 100       11 if ( defined $item ) {
337 3         6 push( @new_ary, $item );
338             }
339             }
340 1         3 @{$self} = @new_ary;
  1         4  
341              
342 1         3 return $self;
343             }
344              
345             =item concat()
346             Append another array to self.
347            
348             ra(1, 2, 3)->concat([4, 5]) # return [1, 2, 3, 4, 5]
349             =cut
350              
351             sub concat {
352 12     12 1 19 my ( $self, $other_ary ) = @_;
353 12 50       28 ref($self) eq __PACKAGE__ or die;
354              
355 12         14 push( @{$self}, @{$other_ary} );
  12         20  
  12         18  
356              
357 12         193 return $self;
358             }
359              
360             =item count()
361             Return the amount of elements
362            
363             ra(1, 2, 3)->count() #return 3
364             ra(1, 2, 2)->count(2) #return 2
365             ra(1, 2, 3)->count( sub { $_[0] > 0 } ) #return 3
366             =cut
367              
368             sub count {
369 3     3 1 6 my ( $self, $obj_or_block ) = @_;
370 3 50       8 ref($self) eq __PACKAGE__ or die;
371              
372 3 100       7 if ( defined $obj_or_block ) {
373 2 100       8 if ( ref($obj_or_block) eq 'CODE' ) {
374 1         2 my $count = 0;
375 1         2 for my $item ( @{$self} ) {
  1         3  
376 3 50       10 if ( $obj_or_block->($item) ) {
377 3         16 $count++;
378             }
379             }
380 1         6 return $count;
381             }
382             else {
383 1         2 my $count = 0;
384 1         2 for my $item ( @{$self} ) {
  1         2  
385 3 100       8 if ( p_obj($obj_or_block) eq p_obj($item) ) {
386 2         6 $count++;
387             }
388             }
389 1         5 return $count;
390             }
391             }
392              
393 1         2 return scalar( @{$self} );
  1         5  
394             }
395              
396             =item cycle()
397             Calls the block for each element n times.
398             It runs forever, if n is not given.
399            
400             ra(1, 2, 3)->cycle(2 , sub { print $_[0] + 1 + ", " }) # print "2, 3, 4, 2, 3, 4, "
401            
402             ra(1, 2, 3)->cycle(sub { print $_[0] + 1 + ", " }) # print "2, 3, 4, 2, 3, 4, .... forever
403             =cut
404              
405             sub cycle {
406 1     1 1 2 my ( $self, $n_or_block, $block_or_n ) = @_;
407 1 50       10 ref($self) eq __PACKAGE__ or die;
408              
409 1 50 33     10 if ( defined $n_or_block && not $block_or_n ) {
410 0 0       0 if ( ref($n_or_block) eq 'CODE' ) {
411 0         0 while (1) {
412 0         0 for my $item ( @{$self} ) {
  0         0  
413 0         0 $n_or_block->($item);
414             }
415             }
416             }
417             }
418             else {
419 1         4 for ( my $i = 0 ; $i < $n_or_block ; $i++ ) {
420 2         2 for my $item ( @{$self} ) {
  2         5  
421 6         14 $block_or_n->($item);
422             }
423             }
424             }
425             }
426              
427             =item delete()
428             Delete all the items in self if equal to the given value, and return it.
429            
430             ra(1, 3, 5)->delete(3); #return 3
431             =cut
432              
433             sub delete {
434 18     18 1 30 my ( $self, $target, $block ) = @_;
435 18 50       56 ref($self) eq __PACKAGE__ or die;
436              
437 18         22 my $before_len = scalar( @{$self} );
  18         32  
438 18         25 @{$self} = grep { p_obj($_) ne p_obj($target) } @{$self};
  18         50  
  33         98  
  18         35  
439              
440 18 100       32 if ( $before_len == scalar( @{$self} ) ) {
  18         46  
441 3 50       9 if ( defined $block ) {
442 0         0 return $block->();
443             }
444 3         7 return undef;
445             }
446             else {
447 15         42 return $target;
448             }
449             }
450              
451             =item delete_at()
452             Delete the element at the given index, and return it.
453            
454             ra(1, 2, 3)->delete_at(2); #return 3
455             =cut
456              
457             sub delete_at {
458 20     20 1 82 my ( $self, $index ) = @_;
459 20 50       54 ref($self) eq __PACKAGE__ or die;
460              
461 20         24 my $target = @{$self}[$index];
  20         50  
462              
463 20 50 33     22 if ( scalar( @{$self} ) == 0 ) {
  20 50 0     73  
  20 0       65  
464 0         0 return undef;
465             }
466 0         0 elsif ( $index >= 0 && $index < scalar( @{$self} ) ) {
467 20         25 splice( @{$self}, $index, 1 );
  20         37  
468 20         65 return $target;
469             }
470             elsif ( $index <= -1 && $index >= -scalar( @{$self} ) ) {
471 0         0 splice( @{$self}, $index, 1 );
  0         0  
472 0         0 return $target;
473             }
474             else {
475 0         0 return undef;
476             }
477             }
478              
479             =item delete_if()
480             Deletes every elements of self if the block evaluates to true.
481            
482             ra(1, 2, 3)->delete_if ( sub { |e| e > 2}); #return ra(1, 2)
483             =cut
484              
485             sub delete_if {
486 1     1 1 7 my ( $self, $block ) = @_;
487 1 50       4 ref($self) eq __PACKAGE__ or die;
488              
489 1         2 @{$self} = grep { !$block->($_) } @{$self};
  1         5  
  3         11  
  1         2  
490              
491 1         2 return $self;
492             }
493              
494             =item drop()
495             Drop first n elements in array and return rest elements in a new array.
496            
497             ra(1, 3, 5, 7, 9)->drop(3); #return ra(7, 9)
498             =cut
499              
500             sub drop {
501 1     1 1 3 my ( $self, $n ) = @_;
502 1 50       4 ref($self) eq __PACKAGE__ or die;
503              
504 1 50       4 if ( $n < 0 ) {
505 0         0 die 'attempt to drop negative size';
506             }
507              
508 1         5 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
509 1         6 for my $i ( 0 .. scalar( @{$self} ) - 1 ) {
  1         4  
510 5 100       15 if ( $i >= $n ) {
511 2         3 push( @new_ary, @{$self}[$i] );
  2         7  
512             }
513             }
514              
515 1         8 return $new_ary;
516             }
517              
518             =item drop_while
519             Drop the elememts up to, but not including, the first element which the block returns false,
520             and return the rest elements as a new array.
521            
522             ra(1, 2, 3, 4, 5, 1, 4)->drop_while( sub { $_[0] < 2 } ); #retrun ra( 2, 3, 4, 5, 1, 4 )
523             =cut
524              
525             sub drop_while {
526 1     1 1 3 my ( $self, $block ) = @_;
527 1 50       4 ref($self) eq __PACKAGE__ or die;
528              
529 1         1 my $cut_point = undef;
530 1         120 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
531 1         7 for my $item ( @{$self} ) {
  1         3  
532 7 100 100     45 if ( ( not $block->($item) ) || $cut_point ) {
533 6         28 $cut_point = 1;
534 6         15 push( @new_ary, $item );
535             }
536             }
537              
538 1         9 return $new_ary;
539             }
540              
541             =item each()
542             Passing each element in self as a parameter to the call block.
543             Alias: each_entry()
544            
545             ra(1, 2, 3)->each(sub { print $_[0] }); #return ra(1, 2, 3)
546             =cut
547              
548             sub each {
549 2     2 1 4 my ( $self, $block ) = @_;
550 2 50       7 ref($self) eq __PACKAGE__ or die;
551              
552 2         4 for my $item ( @{$self} ) {
  2         4  
553 5         78 $block->($item);
554             }
555              
556 2         16 return $self;
557             }
558              
559             =item each_cons()
560             Group each element with (n-1) following members in to an new array until the last element included.
561            
562             ra(1, 2, 3, 4, 5, 6, 7, 8)->each_cons(5); #return ra(ra(1, 2, 3, 4, 5), ra(2, 3, 4, 5, 6), ra(3, 4, 5, 6, 7), ra(4, 5, 6, 7, 8))
563             =cut
564              
565             sub each_cons {
566 3     3 1 6 my ( $self, $n, $block ) = @_;
567 3 50       13 ref($self) eq __PACKAGE__ or die;
568              
569 3 100       22 die 'ArgumentError: invalid size' if ( $n <= 0 );
570              
571 2         11 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
572 2         12 for ( my $i = 0 ; $i < scalar( @{$self} ) ; $i++ ) {
  9         38  
573 7 100       9 if ( $i + $n <= scalar( @{$self} ) ) {
  7         32  
574 5         19 my $cons = tie my @cons, 'Ruby::Collections::Array';
575 5         32 for ( my $j = $i ; $j < $i + $n ; $j++ ) {
576 10         21 $cons->push( $self->at($j) );
577             }
578 5 100       13 if ( defined $block ) {
579 2         7 $block->($cons);
580             }
581             else {
582 3         7 push( @new_ary, $cons );
583             }
584             }
585             }
586              
587 2 100       8 if ( defined $block ) {
588 1         7 return undef;
589             }
590             else {
591 1         4 return $new_ary;
592             }
593             }
594              
595             =item each_entry()
596             Passing each element in self as a parameter to the call block.
597             Alias: each()
598            
599             ra(1, 2, 3)->each_entry(sub { print $_[0] }); #return ra(1, 2, 3)
600             =cut
601              
602             sub each_entry {
603 1     1 1 3 my ( $self, $block ) = @_;
604 1 50       5 ref($self) eq __PACKAGE__ or die;
605              
606 1 50       3 if ( defined $block ) {
607 0         0 for my $item ( @{$self} ) {
  0         0  
608 0         0 $block->($item);
609             }
610             }
611              
612 1         6 return $self;
613             }
614              
615             =item each_index
616             Passing the index of each element to the block.
617            
618             ra(1, 3, 5, 7)->each_index( sub { print $_[0] } ); # print 0123
619             =cut
620              
621             sub each_index {
622 4     4 1 10 my ( $self, $block ) = @_;
623 4 50       17 ref($self) eq __PACKAGE__ or die;
624              
625 4         10 for ( my $i = 0 ; $i < scalar( @{$self} ) ; $i++ ) {
  24         58  
626 20         43 $block->($i);
627             }
628              
629 4         10 return $self;
630             }
631              
632             =item each_slice
633             Group element with (n-1) members in to an new array until the last element included.
634            
635             ra(1, 2, 3, 4, 5)->each_slice(3); #return ra(ra(1, 2, 3), ra(4, 5));
636             =cut
637              
638             sub each_slice {
639 3     3 1 6 my ( $self, $n, $block ) = @_;
640 3 50       16 ref($self) eq __PACKAGE__ or die;
641              
642 3 100 66     37 die 'ArgumentError: invalid slice size'
643             if ( ( not defined $n ) || $n <= 0 );
644              
645 2         10 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
646 2         13 my $blocks =
647 0         0 scalar( @{$self} ) % $n == 0
648 2         10 ? int( scalar( @{$self} ) / $n )
649 2 50       12 : int( scalar( @{$self} ) / $n ) + 1;
650 2         10 for ( my $i = 0 ; $i < $blocks ; $i++ ) {
651 4         30 my $cons = tie my @cons, 'Ruby::Collections::Array';
652 4 100       24 for (
653 12         48 my $j = $i * $n ;
654             $j < scalar( @{$self} ) ? $j < $i * $n + $n : undef ;
655             $j++
656             )
657             {
658 8         20 $cons->push( $self->at($j) );
659             }
660 4 50       13 if ( defined $block ) {
661 0         0 $block->($cons);
662             }
663             else {
664 4         15 push( @new_ary, $cons );
665             }
666             }
667              
668 2 50       20 if ( defined $block ) {
669 0         0 return undef;
670             }
671             else {
672 2         31 return $new_ary;
673             }
674             }
675              
676             =item each_with_index
677             For each item calls block with itself and it's index.
678            
679             ra(1, 2, 3)->each_with_index(sub { $_[1] }); #return ra(0, 1, 2)
680             =cut
681              
682             sub each_with_index {
683 1     1 1 2 my ( $self, $block ) = @_;
684 1 50       5 ref($self) eq __PACKAGE__ or die;
685              
686 1 50       4 if ( defined $block ) {
687 1         2 for ( my $i = 0 ; $i < scalar( @{$self} ) ; $i++ ) {
  4         12  
688 3         5 $block->( @{$self}[$i], $i );
  3         10  
689             }
690             }
691              
692 1         3 return $self;
693             }
694              
695             =item each_with_object
696             Passing each element with an object in a block, return the object in the end.
697            
698             ra( 1, 2, 3 )->each_with_object( ra, sub { $_[1] << $_[0]**2 } ); #return ra( 1, 4, 9 )
699            
700             =cut
701              
702             sub each_with_object {
703 1     1 1 3 my ( $self, $object, $block ) = @_;
704 1 50       5 ref($self) eq __PACKAGE__ or die;
705              
706 1 50       4 if ( defined $block ) {
707 1         2 for my $item ( @{$self} ) {
  1         3  
708 3         7 $block->( $item, $object );
709             }
710             }
711              
712 1         4 return $object;
713             }
714              
715             =item is_empty
716             Return true if the array don't contain any element.
717            
718             ra(1, 2, 3)->is_empty() #return 0;
719             =cut
720              
721             sub is_empty {
722 1     1 1 2 my ($self) = @_;
723 1 50       5 ref($self) eq __PACKAGE__ or die;
724              
725 1 50       2 if ( scalar( @{$self} ) == 0 ) {
  1         3  
726 0         0 return 1;
727             }
728             else {
729 1         6 return 0;
730             }
731             }
732              
733             =item eql
734             Return true if these 2 arrays have same order and content.
735            
736             ra(1, 2, 3)->equal(ra(4, 5, 6)) #return 0
737             =cut
738              
739             sub eql {
740 6     6 1 213 my ( $self, $other ) = @_;
741 6 50       25 ref($self) eq __PACKAGE__ or die;
742              
743 6 50       36 if ( reftype($other) ne 'ARRAY' ) {
744 0         0 return 0;
745             }
746              
747 6 50       10 if ( scalar( @{$self} ) != scalar( @{$other} ) ) {
  6         11  
  6         22  
748 0         0 return 0;
749             }
750              
751 6         10 for ( my $i = 0 ; $i < scalar( @{$self} ) ; $i++ ) {
  11         33  
752 9 100       14 if ( p_obj( @{$self}[$i] ) ne p_obj( @{$other}[$i] ) ) {
  9         40  
  9         33  
753 4         28 return 0;
754             }
755             }
756              
757 2         18 return 1;
758             }
759              
760             =item not_eql
761             Return true if these 2 arrays have different order and content.
762            
763             ra(1, 2, 3)->not_equal(ra(4, 5, 6)) #return 1
764             =cut
765              
766             sub not_eql {
767 3     3 1 12 my ( $self, $other ) = @_;
768 3 50       15 ref($self) eq __PACKAGE__ or die;
769              
770 3 50       12 return $self->eql($other) == 0 ? 1 : 0;
771             }
772              
773             =item fetch()
774             Retrun the element of array from given index.
775             If the given index is out of the scalar of array, it will be seen as an IndexError exception,
776             unless a second argument is given, and which will be a default value.
777             If a block is given, it will be executed when an invalid index is given.
778             If the index is a negative value, the last element of array will be return.
779            
780             ra(1, 2, 3)->fetch(2) #return 3;
781             ra(1, 2, 3)->fetch(5, 6) #return 6;
782             ra(1, 2, 3)->fetch(-1) #return 3;
783             =cut
784              
785             sub fetch {
786 4     4 1 8 my ( $self, $index, $default_value_or_block ) = @_;
787 4 50       13 ref($self) eq __PACKAGE__ or die;
788              
789 4 100 66     5 if ( $index >= scalar( @{$self} ) || $index < -scalar( @{$self} ) ) {
  4         15  
  2         11  
790 2 100       7 if ( defined $default_value_or_block ) {
791 1 50       17 if ( ref($default_value_or_block) eq 'CODE' ) {
792 0         0 return $default_value_or_block->($index);
793             }
794             else {
795 1         5 return $default_value_or_block;
796             }
797             }
798             else {
799 1         3 die( "index "
800             . $index
801             . " outside of array bounds: "
802 1         43 . -scalar( @{$self} ) . "..."
803 1         4 . scalar( @{$self} ) );
804             }
805             }
806 2         8 return $self->at($index);
807             }
808              
809             =item fill
810             Replace all the elements in array by the given value.
811             If the second and third(n) value are given in the same time, means the array will be replace by the given value
812             from the second value of index to the following n elements.
813             If a block is given, it will pass all or given amount of indexs to the block and return the result as an array.
814            
815             ra(1, 2, 3)->fill(4) #return ra(4, 4, 4);
816             ra(1, 2, 3, 4)->fill(sub {$_[0]}) #return ra(0, 1, 2, 3);
817             ra(1, 2, 3, 4)->fill(1, sub { 11 }) #return ra(1, 11, 11, 11);
818             ra(1, 2, 3, 4)->fill('ab', 1) #return ra(1, 'ab', 'ab', 'ab');
819             ra(1, 2, 3, 4)->fill(1, 2, sub { 11 }) #return ra(1, 11, 11, 4);
820             ra(1, 2, 3, 4)->fill('ab', 1, 2) #return ra(1, 'ab', 'ab', 4);
821             =cut
822              
823             sub fill {
824 6 100   6 1 127 if ( @_ == 2 ) {
    100          
    50          
825 2 100       7 if ( ref( $_[1] ) eq 'CODE' ) {
826 1         2 my ( $self, $block ) = @_;
827 1 50       5 ref($self) eq __PACKAGE__ or die;
828              
829 1         3 for ( my $i = 0 ; $i < scalar( @{$self} ) ; $i++ ) {
  5         12  
830 4         9 @{$self}[$i] = $block->($i);
  4         13  
831             }
832              
833 1         6 return $self;
834             }
835             else {
836 1         3 my ( $self, $item ) = @_;
837 1 50       5 ref($self) eq __PACKAGE__ or die;
838              
839 1         4 for ( my $i = 0 ; $i < scalar( @{$self} ) ; $i++ ) {
  4         10  
840 3         4 @{$self}[$i] = $item;
  3         4  
841             }
842              
843 1         5 return $self;
844             }
845             }
846             elsif ( @_ == 3 ) {
847 2 100       89 if ( ref( $_[2] ) eq 'CODE' ) {
848 1         4 my ( $self, $start, $block ) = @_;
849 1 50       7 ref($self) eq __PACKAGE__ or die;
850              
851 1         4 for ( my $i = $start ; $i < scalar( @{$self} ) ; $i++ ) {
  7         20  
852 6         18 @{$self}[$i] = $block->($i);
  6         27  
853             }
854              
855 1         7 return $self;
856             }
857             else {
858 1         3 my ( $self, $item, $start ) = @_;
859 1 50       4 ref($self) eq __PACKAGE__ or die;
860              
861 1         3 for ( my $i = $start ; $i < scalar( @{$self} ) ; $i++ ) {
  4         10  
862 3         4 @{$self}[$i] = $item;
  3         5  
863             }
864              
865 1         5 return $self;
866             }
867             }
868             elsif ( @_ == 4 ) {
869 2 100       9 if ( ref( $_[3] ) eq 'CODE' ) {
870 1         4 my ( $self, $start, $length, $block ) = @_;
871 1 50       5 ref($self) eq __PACKAGE__ or die;
872              
873 1         6 for ( my $i = $start ; $i < $start + $length ; $i++ ) {
874 2         7 @{$self}[$i] = $block->($i);
  2         12  
875             }
876 1         8 return $self;
877             }
878             else {
879 1         2 my ( $self, $item, $start, $length ) = @_;
880 1 50       5 ref($self) eq __PACKAGE__ or die;
881              
882 1         5 for ( my $i = $start ; $i < $start + $length ; $i++ ) {
883 3         3 @{$self}[$i] = $item;
  3         19  
884             }
885              
886 1         5 return $self;
887             }
888             }
889             }
890              
891             =item find
892             Passing each element to the block, and return the first element if block is true, else return undef.
893            
894             ra('a', 'b', 'c', 'b')->find(sub { $_[0] eq 'b' }) return b;
895             =cut
896              
897             sub find {
898 1     1 1 3 my ( $self, $block ) = @_;
899 1 50       5 ref($self) eq __PACKAGE__ or die;
900              
901 1         2 for my $item ( @{$self} ) {
  1         2  
902 2 100       9 if ( $block->($item) ) {
903 1         8 return $item;
904             }
905             }
906              
907 0         0 return undef;
908             }
909              
910             *detect = \&find;
911              
912             =item find_index
913             Return the first index of the given value in the array.
914             If a block instead of an argument, then return the first index of the given value in the array.
915            
916             ra('a', 'b', 'c', 'b')->find_index('b') #return 1;
917             ra('a', 'b', 'c', 'b')->find_index( sub { if($_[0] eq 'b')}) #return 1;
918             =cut
919              
920             sub find_index {
921 2     2 1 5 my ( $self, $obj_or_block ) = @_;
922 2 50       7 ref($self) eq __PACKAGE__ or die;
923              
924 2 100       16 if ( ref($obj_or_block) eq 'CODE' ) {
925 1         3 for ( my $i = 0 ; $i < scalar( @{$self} ) ; $i++ ) {
  2         14  
926 2 100       3 return $i if ( $obj_or_block->( @{$self}[$i] ) );
  2         7  
927             }
928             }
929             else {
930 1         4 for ( my $i = 0 ; $i < scalar( @{$self} ) ; $i++ ) {
  2         5  
931 2         8 return $i
932 2 100       8 if ( p_obj( @{$self}[$i] ) eq p_obj($obj_or_block) );
933             }
934             }
935              
936 0         0 return undef;
937             }
938              
939             =item index
940             Retrun the first index of given object in array.
941            
942             ra('a', 'b', 'c', 'c')->index('c') #return 2;
943             =cut
944              
945             sub index {
946 283     283 1 402 my ( $self, $obj_or_block ) = @_;
947 283 50       676 ref($self) eq __PACKAGE__ or die;
948              
949 283 50       504 if ( ref($obj_or_block) eq 'CODE' ) {
950 0         0 for ( my $i = 0 ; $i < scalar( @{$self} ) ; $i++ ) {
  0         0  
951 0 0       0 if ( $obj_or_block->( @{$self}[$i] ) ) {
  0         0  
952 0         0 return $i;
953             }
954             }
955             }
956             else {
957 283         373 for ( my $i = 0 ; $i < scalar( @{$self} ) ; $i++ ) {
  529         1164  
958 523 100       563 if ( p_obj( @{$self}[$i] ) eq p_obj($obj_or_block) ) {
  523         1563  
959 277         777 return $i;
960             }
961             }
962             }
963              
964 6         15 return undef;
965             }
966              
967             =item inject
968             Combines all elements by applying a binary operation, ex. a block, method or operator.
969            
970             ra(1, 2, 3, 4)->inject(sub { $_[0] + $_[1] }) #return 10;
971             =cut
972              
973             sub inject {
974 3     3 1 8 my $self = shift @_;
975 3 50       12 ref($self) eq __PACKAGE__ or die;
976              
977 3 100       14 if ( @_ == 1 ) {
    50          
978 2         5 my $block = shift @_;
979              
980 2         3 my $out = @{$self}[0];
  2         6  
981 2         6 for ( my $i = 1 ; $i < scalar( @{$self} ) ; $i++ ) {
  7         33  
982 5         7 $out = $block->( $out, @{$self}[$i] );
  5         16  
983             }
984              
985 2         11 return $out;
986             }
987             elsif ( @_ == 2 ) {
988 1         3 my ( $init, $block ) = @_;
989              
990 1         2 my $out = $init;
991 1         3 for ( my $i = 0 ; $i < scalar( @{$self} ) ; $i++ ) {
  4         26  
992 3         6 $out = $block->( $out, @{$self}[$i] );
  3         9  
993             }
994              
995 1         7 return $out;
996             }
997             else {
998 0         0 die 'ArgumentError: wrong number of arguments (' . @_ . ' for 0..2)';
999             }
1000             }
1001              
1002             *reduce = \&inject;
1003              
1004             =item first
1005             Return the first or first n elements of the array.
1006             Return the first n elements of the array as a new array.
1007            
1008             ra(1, 2, 3 ,4)->first #return 1
1009             ra(1, 2, 3 ,4)->first(2) #return ra(1, 2)
1010             =cut
1011              
1012             sub first {
1013 142     142 1 214 my ( $self, $n ) = @_;
1014 142 50       395 ref($self) eq __PACKAGE__ or die;
1015              
1016 142 100       373 if ( defined $n ) {
1017 1 50       4 die 'ArgumentError: negative array size' if ( $n < 0 );
1018              
1019 1         3 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
1020 1   66     10 for ( my $i ; $i < $n && $i < scalar( @{$self} ) ; $i++ ) {
  2         14  
1021 2         4 push( @new_ary, @{$self}[$i] );
  2         9  
1022             }
1023 1         9 return $new_ary;
1024             }
1025             else {
1026 141         175 return @{$self}[0];
  141         955  
1027             }
1028             }
1029              
1030             =item flat_map()
1031             Return a new array with the concatenated result of each element's running block.
1032              
1033             ra(ra('a', 'b', 'c'), ra('d', 'e'))->flat_map(sub {$_[0] + ra('f')}) #return ra('a', 'b', 'c', 'f', 'd', 'e', 'f');
1034             =cut
1035              
1036             sub flat_map {
1037 1     1 1 3 my ( $self, $block ) = @_;
1038 1 50       4 ref($self) eq __PACKAGE__ or die;
1039              
1040 1         4 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
1041             $self->map($block)->each(
1042             sub {
1043 2 50   2   10 if ( reftype( $_[0] ) eq 'ARRAY' ) {
1044 2 50       11 if ( $_[0]->has_any( sub { reftype( $_[0] ) eq 'ARRAY' } ) ) {
  7         32  
1045 0         0 $new_ary->push( $_[0]->flatten(1) );
1046             }
1047             else {
1048 2         8 $new_ary->concat( $_[0] );
1049             }
1050             }
1051             else {
1052 0         0 $new_ary->push( $_[0] );
1053             }
1054             }
1055 1         8 );
1056              
1057 1         9 return $new_ary;
1058             }
1059              
1060             *collect_concat = \&flat_map;
1061              
1062             =item flatten
1063             Return a new array after flattening self into one-dimension.
1064            
1065             ra(ra('a', 'b'), ra('d', 'e'))->flatten #return ra('a', 'b', 'd', 'e');
1066             =cut
1067              
1068             sub flatten {
1069 1     1 1 2 my ( $self, $n ) = @_;
1070 1 50       5 ref($self) eq __PACKAGE__ or die;
1071              
1072 1         3 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
1073 1         6 for my $item ( @{$self} ) {
  1         3  
1074 2 50 33     22 if ( defined $n && $n > 0 && reftype($item) eq 'ARRAY' ) {
    50 33        
      33        
1075 0         0 $new_ary->concat( recursive_flatten( $item, $n - 1 ) );
1076             }
1077             elsif ( !defined $n && reftype($item) eq 'ARRAY' ) {
1078 2         5 $new_ary->concat( recursive_flatten($item) );
1079             }
1080             else {
1081 0         0 push( @new_ary, $item );
1082             }
1083             }
1084              
1085 1         6 return $new_ary;
1086             }
1087              
1088             =item recursive_flatten
1089            
1090             =cut
1091              
1092             sub recursive_flatten {
1093 9 50   9 1 32 caller eq __PACKAGE__ or die;
1094 9         147 my ( $ary, $n ) = @_;
1095              
1096 9         33 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
1097 9         43 for my $item ( @{$ary} ) {
  9         17  
1098 14 50 66     136 if ( defined $n && $n > 0 && reftype($item) eq 'ARRAY' ) {
    50 33        
      66        
1099 0         0 $new_ary->concat( recursive_flatten( $item, $n - 1 ) );
1100             }
1101             elsif ( !defined $n && reftype($item) eq 'ARRAY' ) {
1102 0         0 $new_ary->concat( recursive_flatten($item) );
1103             }
1104             else {
1105 14         35 push( @new_ary, $item );
1106             }
1107             }
1108              
1109 9         70 return $new_ary;
1110             }
1111              
1112             =item flattenEx()
1113             Flattens self in place.
1114            
1115             ra(ra('a', 'b'), ra('d', 'e'))->flattenEx #return ra('a', 'b', 'd', 'e');
1116             =cut
1117              
1118             sub flattenEx {
1119 4     4 1 10 my ( $self, $n ) = @_;
1120 4 50       16 ref($self) eq __PACKAGE__ or die;
1121              
1122 4         16 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
1123 4         23 for my $item ( @{$self} ) {
  4         11  
1124 10 100 66     132 if ( defined $n && $n > 0 && reftype($item) eq 'ARRAY' ) {
    100 100        
      66        
1125 5         11 $new_ary->concat( recursive_flatten( $item, $n - 1 ) );
1126             }
1127             elsif ( !defined $n && reftype($item) eq 'ARRAY' ) {
1128 2         5 $new_ary->concat( recursive_flatten($item) );
1129             }
1130             else {
1131 3         8 push( @new_ary, $item );
1132             }
1133             }
1134 4         29 @{$self} = @new_ary;
  4         36  
1135              
1136 4         51 return $self;
1137             }
1138              
1139             =item grep()
1140             Return all the elements as an array which matches the given pattern.
1141             If a block is supplied, each matching element will be passed to the block, and the result will be collect in an array.
1142            
1143             ra('abbc', 'qubbn', 'accd')->grep('bb') #return ra('abbc', 'qubbn')
1144             ra('abbc', 'qubbn', 'accd')->grep('bb', sub { $_[0] + 'l'}) #return ra('abbcl', 'qubbnl')
1145             =cut
1146              
1147             sub grep {
1148 4     4 1 10 my ( $self, $pattern, $block ) = @_;
1149 4 50       14 ref($self) eq __PACKAGE__ or die;
1150              
1151 4         16 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
1152 4         20 for my $item ( @{$self} ) {
  4         36  
1153 12 100       66 if ( p_obj($item) =~ $pattern ) {
1154 8 100       17 if ( defined $block ) {
1155 4         14 push( @new_ary, $block->($item) );
1156             }
1157             else {
1158 4         11 push( @new_ary, $item );
1159             }
1160             }
1161             }
1162              
1163 4         36 return $new_ary;
1164             }
1165              
1166             =item group_by
1167             Return a hash which key is the block result and the values are arrays of elements which related with the key.
1168            
1169             ra(1, 2, 3, 4)->group_by( sub { $_[0]%3 }) #return rh( 1=>[1, 4], 2=>[2], 0=>[3]);
1170             =cut
1171              
1172             sub group_by {
1173 1     1 1 2 my ( $self, $block ) = @_;
1174 1 50       5 ref($self) eq __PACKAGE__ or die;
1175              
1176 1         8 my $new_hash = tie my %new_hash, 'Ruby::Collections::Hash';
1177 1         2 for my $item ( @{$self} ) {
  1         3  
1178 4         11 my $key = $block->($item);
1179 4 100       86 if ( $new_hash->{$key} ) {
1180 1         6 $new_hash->{$key}->push($item);
1181             }
1182             else {
1183 3         12 $new_hash->{$key} = tie my @group, 'Ruby::Collections::Array';
1184 3         15 $new_hash->{$key}->push($item);
1185             }
1186             }
1187              
1188 1         7 return $new_hash;
1189             }
1190              
1191             =iten include()
1192             Return true if any element equals the given object.
1193            
1194             ra(1, 3, 5, 7, 9)->include(9) #return true #
1195             =cut
1196              
1197             sub include {
1198 29     29 0 45 my ( $self, $obj ) = @_;
1199 29 50       73 ref($self) eq __PACKAGE__ or die;
1200              
1201 29         36 for my $item ( @{$self} ) {
  29         58  
1202 65 100       163 if ( p_obj($item) eq p_obj($obj) ) {
1203 15         88 return 1;
1204             }
1205             }
1206              
1207 14         65 return 0;
1208             }
1209              
1210             *has_member = \&include;
1211              
1212             =item replace()
1213             Replace all elements of self by the other elements of given array.
1214            
1215             ra(1, 4, 6)->replace(ra(2, 5)) #return ra(2, 5);
1216             =cut
1217              
1218             sub replace {
1219 1     1 1 3 my ( $self, $other_ary ) = @_;
1220 1 50       4 ref($self) eq __PACKAGE__ or die;
1221              
1222 1 50       6 if ( reftype($other_ary) eq 'ARRAY' ) {
1223 1         3 @{$self} = @{$other_ary};
  1         4  
  1         2  
1224             }
1225             else {
1226 0         0 die 'TypeError: no implicit conversion of '
1227             . reftype($other_ary)
1228             . ' into Array';
1229             }
1230              
1231 1         4 return $self;
1232             }
1233              
1234             =item insert()
1235             Insert the given value at the given index.
1236            
1237             ra(1, 2, 3, 4)->insert(2, 5) #return ra(1, 2, 5, 3, 4);
1238             ra(1, 2, 3 ,4)->insert(-2, 5) #return ra(1, 2, 3, 5, 4);#
1239             =cut
1240              
1241             sub insert {
1242 3     3 1 5 my $self = shift(@_);
1243 3         4 my $index = shift(@_);
1244              
1245 3 50       4 if ( $index < -scalar( @{$self} ) ) {
  3 100       12  
  3         7  
1246 0         0 die( "IndexError: index "
1247             . $index
1248             . " too small for array; minimum: "
1249 0         0 . -scalar( @{$self} ) );
1250             }
1251             elsif ( $index > scalar( @{$self} ) ) {
1252 1         3 for ( my $i = scalar( @{$self} ) ; $i < $index ; $i++ ) {
  1         7  
1253 2         4 push( @{$self}, undef );
  2         9  
1254             }
1255 1         2 splice( @{$self}, $index, 0, @_ );
  1         5  
1256             }
1257             else {
1258 2 100       3 splice( @{$self}, $index < 0 ? $index + 1 : $index, 0, @_ );
  2         8  
1259             }
1260              
1261 3         14 return $self;
1262             }
1263              
1264             =item inspect()
1265             Return the object as string.
1266            
1267             ra(1, 2, 3)->inspect() #return 'ra(1, 2, 3)'; #
1268             =cut
1269              
1270             sub inspect {
1271 272     272 1 377 my ($self) = @_;
1272 272 50       626 ref($self) eq __PACKAGE__ or die;
1273              
1274 272         841 return p_array $self;
1275             }
1276              
1277             =item to_s()
1278             ra(1, 2, 3)->inspect() #return 'ra(1, 2, 3)';
1279             =cut
1280              
1281             sub to_s {
1282 271     271 1 28068 my ($self) = @_;
1283 271 50       788 ref($self) eq __PACKAGE__ or die;
1284              
1285 271         688 return $self->inspect;
1286             }
1287              
1288             =item join()
1289             Return a string created by converting each element of array to a string, merged by the given separator.
1290            
1291             ra('a', 'b', 'c')->join("/") #return 'a/b/c';
1292             =cut
1293              
1294             sub join {
1295 3153     3153 1 4454 my ( $self, $separator ) = @_;
1296 3153 50       6946 ref($self) eq __PACKAGE__ or die;
1297              
1298 3153 50       5365 if ( defined $separator ) {
1299 3153         3315 return join( $separator, @{$self} );
  3153         15573  
1300             }
1301             else {
1302 0         0 return join( '', @{$self} );
  0         0  
1303             }
1304             }
1305              
1306             =item keep_if()
1307             Delete the element of self for which the given block evaluates to false.
1308            
1309             ra(1, 2, 3)->keep_if(sub {$_[0] > 2}) #return ra(3);
1310             =cut
1311              
1312             sub keep_if {
1313 1     1 1 3 my ( $self, $block ) = @_;
1314 1 50       5 ref($self) eq __PACKAGE__ or die;
1315              
1316 1         2 @{$self} = grep { $block->($_) } @{$self};
  1         5  
  3         11  
  1         2  
1317              
1318 1         4 return $self;
1319             }
1320              
1321             =item last()
1322             Return the last or last n elements of self.
1323            
1324             ra(1, 2, 3)->last #return 3;
1325             ra(1, 2, 3)->last(2) #return ra(2, 3);
1326             =cut
1327              
1328             sub last {
1329 14     14 1 23 my ( $self, $n ) = @_;
1330 14 50       41 ref($self) eq __PACKAGE__ or die;
1331              
1332 14 100       35 if ( defined $n ) {
1333 1         6 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
1334 1   66     6 for (
1335 1         11 my $i = scalar( @{$self} ) - 1 ;
  3         26  
1336             $i >= 0 && $i > scalar( @{$self} ) - 1 - $n ;
1337             $i--
1338             )
1339             {
1340 2         6 unshift( @new_ary, @{$self}[$i] );
  2         13  
1341             }
1342 1         8 return $new_ary;
1343             }
1344             else {
1345 13         15 return @{$self}[-1];
  13         57  
1346             }
1347             }
1348              
1349             =item length()
1350             Retrun the number of elements of self.
1351            
1352             ra(1, 2, 3)->length() #return 3;
1353             ra()->length() #return 0;
1354             =cut
1355              
1356             sub length {
1357 3     3 1 5 my ($self) = @_;
1358 3 50       14 ref($self) eq __PACKAGE__ or die;
1359              
1360 3         14 return scalar( @{$self} );
  3         13  
1361             }
1362              
1363             *size = \&length;
1364              
1365             =item map()
1366             Transform each element and store them into a new Ruby::Collections::Array.
1367             Alias: collect()
1368             =cut
1369              
1370             sub map {
1371 5     5 1 10 my ( $self, $block ) = @_;
1372 5 50       15 ref($self) eq __PACKAGE__ or die;
1373              
1374 5         19 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
1375 5         24 for my $item ( @{$self} ) {
  5         12  
1376 20         109 push( @new_ary, $block->($item) );
1377             }
1378              
1379 5         45 return $new_ary;
1380             }
1381              
1382             *collect = \↦
1383              
1384             =item mapEx()
1385             Transform each element and store them in self.
1386             Alias: collectEx()
1387             =cut
1388              
1389             sub mapEx {
1390 10     10 1 34 my ( $self, $block ) = @_;
1391 10 50       40 ref($self) eq __PACKAGE__ or die;
1392              
1393 10         19 my @new_ary;
1394 10         18 for my $item ( @{$self} ) {
  10         26  
1395 34         94 push( @new_ary, $block->($item) );
1396             }
1397 10         30 @{$self} = @new_ary;
  10         40  
1398              
1399 10         29 return $self;
1400             }
1401              
1402             *collectEx = \&mapEx;
1403              
1404             =item max()
1405             Return the max value of object.
1406             If a block is given,
1407            
1408             ra(1, 2, 3)->max() #return 3;
1409             ra(1, 2, 3)->max(sub {$_[1] <=> $_[0]}) #return 1;
1410             =cut
1411              
1412             sub max {
1413 4     4 1 10 my ( $self, $block ) = @_;
1414 4 50       15 ref($self) eq __PACKAGE__ or die;
1415              
1416 4 100       14 if ( defined $block ) {
1417 2         8 return $self->sort($block)->last;
1418             }
1419             else {
1420 2         13 return $self->sort->last;
1421             }
1422             }
1423              
1424             =item max_by()
1425             Return the object that gives the maximum value from the given block.
1426            
1427             ra('avv', 'aldivj', 'kgml')->max_by(sub {length($_[0])}) #return 'aldivj';
1428             =cut
1429              
1430             sub max_by {
1431 2     2 1 7 my ( $self, $block ) = @_;
1432 2 50       9 ref($self) eq __PACKAGE__ or die;
1433              
1434 2         13 return $self->sort_by($block)->last;
1435             }
1436              
1437             =item min()
1438             Return the min value of object.
1439             If a block is given,
1440            
1441             ra(1, 2, 3)->min() #return 1;
1442             ra(1, 2, 3)->min(sub {$_[1] <=> $_[0]}) #return 3;
1443             =cut
1444              
1445             sub min {
1446 4     4 1 9 my ( $self, $block ) = @_;
1447 4 50       43 ref($self) eq __PACKAGE__ or die;
1448              
1449 4 100       15 if ( defined $block ) {
1450 2         11 return $self->sort($block)->first;
1451             }
1452             else {
1453 2         10 return $self->sort->first;
1454             }
1455             }
1456              
1457             =item min_by()
1458             Return the object that gives the minimum value from the given block.
1459            
1460             ra('kv', 'aldivj', 'kgml')->min_by(sub {length($_[0])}) #return 'kv';
1461             =cut
1462              
1463             sub min_by {
1464 2     2 1 6 my ( $self, $block ) = @_;
1465 2 50       15 ref($self) eq __PACKAGE__ or die;
1466              
1467 2         13 return $self->sort_by($block)->first;
1468             }
1469              
1470             =item minmax()
1471             Return an array which contains the minimum and maximum value.
1472            
1473             ra(1, 2, 3)->minmax #return ra(1, 3);
1474             ra('bbb', 'foekvv', 'rd')->minmax(sub{length($_[0]) <=> length($_[1])}) #return ra('rd', 'foekvv');
1475             =cut
1476              
1477             sub minmax {
1478 4     4 1 10 my ( $self, $block ) = @_;
1479 4 50       15 ref($self) eq __PACKAGE__ or die;
1480              
1481 4 100       14 if ( defined $block ) {
1482 2         11 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
1483 2         55 my $sorted_ary = $self->sort($block);
1484 2         9 $new_ary->push( $sorted_ary->first );
1485 2         9 $new_ary->push( $sorted_ary->last );
1486 2         13 return $new_ary;
1487             }
1488             else {
1489 2         10 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
1490 2         15 my $sorted_ary = $self->sort();
1491 2         8 $new_ary->push( $sorted_ary->first );
1492 2         10 $new_ary->push( $sorted_ary->last );
1493 2         12 return $new_ary;
1494             }
1495             }
1496              
1497             =item minmax_by()
1498             Return an array which contains the objects that correspond to the minimum and maximum value respectively from the given block.
1499            
1500             ra('heard', 'see', 'thinking')->minmax_by(sub {length($_[0])}) #return ra('see', 'thinking');
1501             =cut
1502              
1503             sub minmax_by {
1504 2     2 1 5 my ( $self, $block ) = @_;
1505 2 50       12 ref($self) eq __PACKAGE__ or die;
1506              
1507 2         9 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
1508 2         19 my $sorted_ary = $self->sort_by($block);
1509 2         11 $new_ary->push( $sorted_ary->first );
1510 2         8 $new_ary->push( $sorted_ary->last );
1511 2         15 return $new_ary;
1512             }
1513              
1514             =item has_none()
1515             Pass each element to the given block, this method returns true if the block never returns true for all elements.
1516             If the block is not given, this method returns true if all the elements are flase.
1517            
1518             ra(99, 43, 65)->has_none(sub {$_[0] < 50}) #return 0;
1519             ra()->has_none #return 1;
1520             =cut
1521              
1522             sub has_none {
1523 2     2 1 4 my ( $self, $block ) = @_;
1524 2 50       9 ref($self) eq __PACKAGE__ or die;
1525              
1526 2 100       7 if ( defined $block ) {
1527 1         2 for my $item ( @{$self} ) {
  1         5  
1528 2 100       11 return 0 if ( $block->($item) );
1529             }
1530             }
1531             else {
1532 1         2 for my $item ( @{$self} ) {
  1         3  
1533 0 0       0 return 0 if ($item);
1534             }
1535             }
1536              
1537 1         6 return 1;
1538             }
1539              
1540             =item has_one()
1541             Pass each element to the given block, this method returns true if the block returns true exactly once.
1542             If the block is not given, this method returns true if only one elements is true.
1543            
1544             ra(99, 43, 65)->has_one(sub {$_[0] < 50}) #return 1;
1545             ra(100)->has_one #return 1;
1546             =cut
1547              
1548             sub has_one {
1549 2     2 1 4 my ( $self, $block ) = @_;
1550 2 50       8 ref($self) eq __PACKAGE__ or die;
1551              
1552 2         3 my $count = 0;
1553 2 100       6 if ( defined $block ) {
1554 1         3 for my $item ( @{$self} ) {
  1         3  
1555 3 100       15 if ( $block->($item) ) {
1556 1         7 $count++;
1557 1 50       15 return 0 if ( $count > 1 );
1558             }
1559             }
1560             }
1561             else {
1562 1         2 for my $item ( @{$self} ) {
  1         2  
1563 1 50       4 if ($item) {
1564 1         3 $count++;
1565 1 50       4 return 0 if ( $count > 1 );
1566             }
1567             }
1568             }
1569              
1570 2 50       16 return $count == 1 ? 1 : 0;
1571             }
1572              
1573             =item partition()
1574             Return an array which contains two elements.
1575             The first are the objects which evaluate the block to true.
1576             The second are the rest.
1577            
1578             ra(1, 2, 3, 4, 5, 6, 7)->partition(sub {$_[0] % 2 == 0}) #return ra(ra(2, 4, 6), ra(1, 3, 5, 7));
1579             =cut
1580              
1581             sub partition {
1582 1     1 1 3 my ( $self, $block ) = @_;
1583 1 50       5 ref($self) eq __PACKAGE__ or die;
1584              
1585 1         5 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
1586 1         8 my $true_ary = tie my @true_ary, 'Ruby::Collections::Array';
1587 1         7 my $false_ary = tie my @false_ary, 'Ruby::Collections::Array';
1588              
1589 1         5 for my $item ( @{$self} ) {
  1         4  
1590 7 100       35 if ( $block->($item) ) {
1591 3         14 push( @true_ary, $item );
1592             }
1593             else {
1594 4         22 push( @false_ary, $item );
1595             }
1596             }
1597 1         7 push( @new_ary, $true_ary, $false_ary );
1598              
1599 1         9 return $new_ary;
1600             }
1601              
1602             =item permutation()
1603             If a block is given, then return self as all kind of permutations.
1604             If a parameter(n) is given, and also a block, then return self as all kind of permutations in length n.
1605             If a block is not given, then return
1606            
1607             ra(1, 2, 3)->permutation()
1608             =cut
1609              
1610             sub permutation {
1611 1     1 1 3 my ( $self, $n, $block ) = @_;
1612 1 50       6 ref($self) eq __PACKAGE__ or die;
1613              
1614 1         12 my $combinat =
1615 1         3 Math::Combinatorics->new( count => $n, data => [ @{$self} ] );
1616              
1617 1         85 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
1618 1 50       10 if ( $n < 0 ) {
1619 0 0       0 if ( defined $block ) {
1620 0         0 return $self;
1621             }
1622             else {
1623 0         0 return $new_ary;
1624             }
1625             }
1626 1 50       7 if($n == undef) {
1627 1         6 $n = $self->size();
1628             }
1629 1 50       9 if ( $n == 0 ) {
1630 0 0       0 if ( defined $block ) {
1631 0         0 $block->( tie my @empty_ary, 'Ruby::Collections::Array' );
1632 0         0 return $self;
1633             }
1634             else {
1635 0         0 push( @new_ary, tie my @empty_ary, 'Ruby::Collections::Array' );
1636 0         0 return $new_ary;
1637             }
1638             }
1639              
1640 1         5 my $combos = $self->combination($n);
1641 1         3 for my $combo ( @{$combos} ) {
  1         5  
1642 1         6 my $combinat =
1643 1         3 Math::Combinatorics->new( count => $n, data => [ @{$combo} ] );
1644 1         36 while ( my @permu = $combinat->next_permutation ) {
1645 2         86 my $p = tie my @p, 'Ruby::Collections::Array';
1646 2         15 @p = @permu;
1647 2 50       29 if ( defined $block ) {
1648 0         0 $block->($p);
1649             }
1650             else {
1651 2         7 push( @new_ary, $p );
1652             }
1653             }
1654             }
1655              
1656 1 50       58 if ( defined $block ) {
1657 0         0 return $self;
1658             }
1659             else {
1660 1         192 return $new_ary;
1661             }
1662             }
1663              
1664             =item pop()
1665             Return the last element.
1666             If a number n is given, then return the last n elements as an array.
1667            
1668             ra(1, 2, 3)->pop #return 3;
1669             ra(1, 2, 3)->pop(2) #return ra(2, 3);
1670             =cut
1671              
1672             sub pop {
1673 6     6 1 141 my ( $self, $n ) = @_;
1674 6 50       23 ref($self) eq __PACKAGE__ or die;
1675              
1676 6 100       13 if ( defined $n ) {
1677 1 50       8 die 'ArgumentError: negative array size' if ( $n < 0 );
1678              
1679 1         5 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
1680 1   66     12 for ( my $i ; $i < $n && scalar( @{$self} ) != 0 ; $i++ ) {
  2         16  
1681 2         3 unshift( @new_ary, pop( @{$self} ) );
  2         9  
1682             }
1683 1         11 return $new_ary;
1684             }
1685             else {
1686 5         8 return pop( @{$self} );
  5         30  
1687             }
1688             }
1689              
1690             =item product()
1691             Return an array of all combinations of all arrays.
1692             #block
1693            
1694             ra(1, 2)->product(ra(2,3)) #return ra(ra(1, 2), ra(1, 3), ra(2, 2), ra(2, 3));
1695             =cut
1696              
1697             sub product {
1698 1     1 1 2 my ($self) = @_;
1699 1 50       5 ref($self) eq __PACKAGE__ or die;
1700              
1701 1         3 my $block = undef;
1702 1 50       4 if ( ref( $_[-1] ) eq 'CODE' ) {
1703 0         0 $block = pop @_;
1704             }
1705              
1706 1         3 my $array_of_arrays = [];
1707 1         4 for my $item (@_) {
1708 2         4 my @array = @{$item};
  2         4  
1709 2         3 push( @{$array_of_arrays}, \@array );
  2         6  
1710             }
1711              
1712 1         6 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
1713 1         12 my $iterator = Set::CrossProduct->new($array_of_arrays);
1714 1         45 while ( $iterator->next ) {
1715 4         105 my $tuple = tie my @tuple, 'Ruby::Collections::Array';
1716 4         21 @tuple = @{ $iterator->get };
  4         13  
1717 4 50       180 if ( defined $block ) {
1718 0         0 $block->($tuple);
1719             }
1720             else {
1721 4         13 push( @new_ary, $tuple );
1722             }
1723             }
1724              
1725 1 50       13 if ( defined $block ) {
1726 0         0 return $self;
1727             }
1728             else {
1729 1         14 return $new_ary;
1730             }
1731             }
1732              
1733             =item push()
1734             Appending the given array to self, then return it.
1735            
1736             ra(1, 2, 3)->push(5, 6) #return ra(1, 2, 3, 5, 6);
1737             =cut
1738              
1739             sub push {
1740 3709     3709 1 5344 my $self = shift @_;
1741 3709 50       9506 ref($self) eq __PACKAGE__ or die;
1742              
1743 3709         3738 push( @{$self}, @_ );
  3709         7989  
1744              
1745 3709         12810 return $self;
1746             }
1747              
1748             =item double_left_arrows()
1749             Alias : push()
1750             =cut
1751              
1752             sub double_left_arrows {
1753 16     16 1 57 my $self = shift @_;
1754 16 50       34 ref($self) eq __PACKAGE__ or die;
1755              
1756 16         16 push( @{$self}, $_[0] );
  16         28  
1757              
1758 16         42 return $self;
1759             }
1760              
1761             =item rassoc()
1762             Returns the first array which contains the target object as the last element.
1763            
1764             ra(ra(1, 3), 3, ra(2, 3))->rassoc(3) #returns ra(1, 3);
1765             =cut
1766              
1767             sub rassoc {
1768 1     1 1 3 my ( $self, $target ) = @_;
1769 1 50       5 ref($self) eq __PACKAGE__ or die;
1770              
1771 1         2 for my $item ( @{$self} ) {
  1         3  
1772 1 50       7 if ( reftype($item) eq 'ARRAY' ) {
1773 1         3 my @sub_array = @{$item};
  1         3  
1774 1 50       6 if ( p_obj( $sub_array[-1] ) eq p_obj($target) ) {
1775 1         4 my $ret = tie my @ret, 'Ruby::Collections::Array';
1776 1         6 @ret = @sub_array;
1777 1         15 return $ret;
1778             }
1779             }
1780             }
1781              
1782 0         0 return undef;
1783             }
1784              
1785             =item reject()
1786             Return a new array contains the elements from self for which the given block is not true.
1787             Alias: delete_if()
1788            
1789             ra(1, 2, 3)->reject(sub { $_[0] < 3 }) #return ra(3);
1790             =cut
1791              
1792             sub reject {
1793 1     1 1 5 my ( $self, $block ) = @_;
1794 1 50       7 ref($self) eq __PACKAGE__ or die;
1795              
1796 1         7 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
1797 1         6 @new_ary = grep { !$block->($_) } @{$self};
  3         16  
  1         3  
1798              
1799 1         18 return $new_ary;
1800             }
1801              
1802             =item rejectEx()
1803             Delete all the elements from self for which the given block is true.
1804            
1805             ra(1, 2, 3)->rejectEx(sub { $_[0] < 3 }) #return ra(3);
1806             =cut
1807              
1808             sub rejectEx {
1809 1     1 1 3 my ( $self, $block ) = @_;
1810 1 50       6 ref($self) eq __PACKAGE__ or die;
1811              
1812 1         3 my $before_len = scalar( @{$self} );
  1         2  
1813 1         3 @{$self} = grep { !$block->($_) } @{$self};
  1         8  
  3         14  
  1         3  
1814              
1815 1 50       2 if ( scalar( @{$self} ) == $before_len ) {
  1         22  
1816 0         0 return undef;
1817             }
1818             else {
1819 1         4 return $self;
1820             }
1821             }
1822              
1823             =item repeated_combination()
1824             Returns the array which lists all the repeated combinations of length n of all elements from array.
1825            
1826             ra(1, 2, 3)->repeated_combination(2) #returns ra(ra(1, 1), ra(1, 2), ra(1, 3), ra(2, 2), ra(2, 3), ra(3, 3));
1827             =cut
1828              
1829             sub repeated_combination {
1830 1     1 1 4 my ( $self, $n, $block ) = @_;
1831 1 50       5 ref($self) eq __PACKAGE__ or die;
1832              
1833 1         5 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
1834 1 50       9 if ( $n < 0 ) {
1835 0 0       0 if ( defined $block ) {
1836 0         0 return $self;
1837             }
1838             else {
1839 0         0 return $new_ary;
1840             }
1841             }
1842 1 50       7 if ( $n == 0 ) {
1843 0 0       0 if ( defined $block ) {
1844 0         0 $block->( tie my @empty_ary, 'Ruby::Collections::Array' );
1845 0         0 return $self;
1846             }
1847             else {
1848 0         0 push( @new_ary, tie my @empty_ary, 'Ruby::Collections::Array' );
1849 0         0 return $new_ary;
1850             }
1851             }
1852              
1853             repeated_combination_loop(
1854 1         11 $n, 0,
1855             scalar( @{$self} ) - 1,
1856             sub {
1857 6     6   22 my $comb = tie my @comb, 'Ruby::Collections::Array';
1858 6         32 for ( my $i = 0 ; $i < scalar( @{ $_[0] } ) ; $i++ ) {
  18         89  
1859 12         13 push( @comb, @{$self}[ @{ $_[0] }[$i] ] );
  12         32  
  12         21  
1860             }
1861 6 50       13 if ( defined $block ) {
1862 0         0 $block->($comb);
1863             }
1864             else {
1865 6         15 push( @new_ary, $comb );
1866             }
1867             }
1868 1         2 );
1869              
1870 1 50       17 if ( defined $block ) {
1871 0         0 return $self;
1872             }
1873             else {
1874 1         7 return $new_ary;
1875             }
1876             }
1877              
1878              
1879             sub repeated_combination_loop {
1880 1 50   1 0 8 caller eq __PACKAGE__ or die;
1881              
1882 1         23 my ( $layer, $start, $end, $block ) = @_;
1883 1         5 my @counter = ($start) x $layer;
1884 1         3 my $loop_counter = \@counter;
1885              
1886 1         4 my @end_status = ($end) x scalar(@$loop_counter);
1887 1         3 do {
1888 5         13 $block->($loop_counter);
1889 5         42 increase_repeated_combination_loop_counter( $loop_counter, $start,
1890             $end );
1891             } until ( "@$loop_counter" eq "@end_status" );
1892 1         4 $block->($loop_counter);
1893             }
1894              
1895             =item increase_repeated_combination_loop_counter()
1896             =cut
1897              
1898             sub increase_repeated_combination_loop_counter {
1899 5 50   5 1 13 caller eq __PACKAGE__ or die;
1900              
1901 5         86 my ( $loop_counter, $start, $end ) = @_;
1902              
1903 5         16 for my $i ( reverse( 0 .. scalar(@$loop_counter) - 1 ) ) {
1904 5 100 33     23 if ( $loop_counter->[$i] < $end ) {
    50          
1905 3         5 $loop_counter->[$i]++;
1906 3         20 last;
1907             }
1908             elsif ( $i != 0
1909             and $loop_counter->[ $i - 1 ] != $end )
1910             {
1911 2         5 $loop_counter->[ $i - 1 ]++;
1912 2         6 for my $j ( $i .. scalar(@$loop_counter) - 1 ) {
1913 2         8 $loop_counter->[$j] = $loop_counter->[ $i - 1 ];
1914             }
1915 2         11 last;
1916             }
1917             }
1918             }
1919              
1920             =item repeated_permutation()
1921             Returns the array which lists all the repeated permutations of length n of all elements from array.
1922            
1923             ra(1, 2)->repeated_permutation(2) #returns ra(ra(1, 1), ra(1, 2), ra(2, 1), ra(2, 2));
1924             =cut
1925              
1926             sub repeated_permutation {
1927 1     1 1 3 my ( $self, $n, $block ) = @_;
1928 1 50       7 ref($self) eq __PACKAGE__ or die;
1929              
1930 1         5 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
1931 1 50       9 if ( $n < 0 ) {
1932 0 0       0 if ( defined $block ) {
1933 0         0 return $self;
1934             }
1935             else {
1936 0         0 return $new_ary;
1937             }
1938             }
1939 1 50       4 if ( $n == 0 ) {
1940 0 0       0 if ( defined $block ) {
1941 0         0 $block->( tie my @empty_ary, 'Ruby::Collections::Array' );
1942 0         0 return $self;
1943             }
1944             else {
1945 0         0 push( @new_ary, tie my @empty_ary, 'Ruby::Collections::Array' );
1946 0         0 return $new_ary;
1947             }
1948             }
1949              
1950             repeated_permutation_loop(
1951 1         9 $n, 0,
1952             scalar( @{$self} ) - 1,
1953             sub {
1954 4     4   20 my $comb = tie my @comb, 'Ruby::Collections::Array';
1955 4         24 for ( my $i = 0 ; $i < scalar( @{ $_[0] } ) ; $i++ ) {
  12         141  
1956 8         12 push( @comb, @{$self}[ @{ $_[0] }[$i] ] );
  8         29  
  8         14  
1957             }
1958 4 50       12 if ( defined $block ) {
1959 0         0 $block->($comb);
1960             }
1961             else {
1962 4         13 push( @new_ary, $comb );
1963             }
1964             }
1965 1         3 );
1966              
1967 1 50       17 if ( defined $block ) {
1968 0         0 return $self;
1969             }
1970             else {
1971 1         8 return $new_ary;
1972             }
1973             }
1974              
1975             sub repeated_permutation_loop {
1976 1 50   1 0 16 caller eq __PACKAGE__ or die;
1977              
1978 1         34 my ( $layer, $start, $end, $block ) = @_;
1979 1         5 my @counter = ($start) x $layer;
1980 1         3 my $loop_counter = \@counter;
1981              
1982 1         5 my @end_status = ($end) x scalar(@$loop_counter);
1983 1         4 do {
1984 3         8 $block->($loop_counter);
1985 3         31 increase_repeated_permutation_loop_counter( $loop_counter, $start,
1986             $end );
1987             } until ( "@$loop_counter" eq "@end_status" );
1988 1         3 $block->($loop_counter);
1989             }
1990              
1991             sub increase_repeated_permutation_loop_counter {
1992 3 50   3 0 10 caller eq __PACKAGE__ or die;
1993              
1994 3         49 my ( $loop_counter, $start, $end ) = @_;
1995              
1996 3         10 for my $i ( reverse( 0 .. scalar(@$loop_counter) - 1 ) ) {
1997 3 100 33     19 if ( $loop_counter->[$i] < $end ) {
    50          
1998 2         4 $loop_counter->[$i]++;
1999 2         15 last;
2000             }
2001             elsif ( $i != 0
2002             and $loop_counter->[ $i - 1 ] != $end )
2003             {
2004 1         14 $loop_counter->[ $i - 1 ]++;
2005 1         5 for my $j ( $i .. scalar(@$loop_counter) - 1 ) {
2006 1         4 $loop_counter->[$j] = $start;
2007             }
2008 1         7 last;
2009             }
2010             }
2011             }
2012              
2013             =item reverse()
2014             Returns a new array which contains self's elements in the reverse order.
2015            
2016             ra(1, 2, 3)->reverse() #returns ra(3, 2, 1);
2017             =cut
2018              
2019             sub reverse {
2020 2     2 1 6 my ($self) = @_;
2021 2 50       9 ref($self) eq __PACKAGE__ or die;
2022              
2023 2         9 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
2024 2         11 @new_ary = reverse( @{$self} );
  2         9  
2025              
2026 2         38 return $new_ary;
2027             }
2028              
2029             =item reverseEx()
2030             Returns self where all the elements list in the reverse order.
2031            
2032             ra(1, 2, 3)->reverseEx() #returns ra(3, 2, 1);
2033             =cut
2034              
2035             sub reverseEx {
2036 2     2 1 5 my ($self) = @_;
2037 2 50       10 ref($self) eq __PACKAGE__ or die;
2038              
2039 2         9 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
2040 2         12 @{$self} = reverse( @{$self} );
  2         9  
  2         4  
2041              
2042 2         8 return $self;
2043             }
2044              
2045             =item reverse_each()
2046             Passing all the elements to the block, but in the reverse order.
2047            
2048             ra(1, 2, 3)->reverse_each(sub {$_[0]}) #returns ra(3, 2, 1);
2049             =cut
2050              
2051             sub reverse_each {
2052 1     1 1 3 my ( $self, $block ) = @_;
2053 1 50       5 ref($self) eq __PACKAGE__ or die;
2054              
2055 1         4 my $new_ary = $self->reverse;
2056 1 50       4 if ( defined $block ) {
2057 1         3 for my $item ($new_ary) {
2058 1         5 $block->($item);
2059             }
2060             }
2061              
2062 1         9 return $new_ary;
2063             }
2064              
2065             =item rindex()
2066             Returns the index of last object which equal to given object.
2067             If a block is given, returns the index of the last object for which the block returns true.
2068            
2069             ra(1, 2, 3, 2, 4)->rindex(2) #returns 3;
2070             ra(1, 2, 3, 2, 4)->rindex(sub {$_[0] == 2}) #returns 3;
2071             =cut
2072              
2073             sub rindex {
2074 2     2 1 5 my ( $self, $obj_or_block ) = @_;
2075 2 50       8 ref($self) eq __PACKAGE__ or die;
2076              
2077 2 100       8 if ( ref($obj_or_block) eq 'CODE' ) {
2078 1         2 for ( my $i = scalar( @{$self} ) - 1 ; $i >= 0 ; $i-- ) {
  1         6  
2079 2 100       10 if ( $obj_or_block->( @{$self}[$i] ) ) {
  2         8  
2080 1         9 return $i;
2081             }
2082             }
2083             }
2084             else {
2085 1         5 for ( my $i = scalar( @{$self} ) - 1 ; $i >= 0 ; $i-- ) {
  1         8  
2086 2 100       4 if ( p_obj( @{$self}[$i] ) eq p_obj($obj_or_block) ) {
  2         9  
2087 1         8 return $i;
2088             }
2089             }
2090             }
2091              
2092 0         0 return undef;
2093             }
2094              
2095             =item rotate()
2096             Returns a new array by rotating self, the element at given number is the first element of new array.
2097             If the given number is negative, then statring from the end of self.
2098            
2099             ra(1, 2, 3)->rotate() #return ra(2, 3, 1);
2100             ra(1, 2, 3)->rotate(2) #return ra(3, 1, 2);
2101             ra(1, 2, 3)->rotate(-2) #return ra(2, 3, 1);
2102             =cut
2103              
2104             sub rotate {
2105 3     3 1 8 my ( $self, $count ) = @_;
2106 3 50       11 ref($self) eq __PACKAGE__ or die;
2107              
2108 3 100       9 $count = 1 if ( not defined $count );
2109              
2110 3         14 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
2111 3         18 @new_ary = @{$self};
  3         13  
2112 3 50       53 if ( scalar( @{$self} ) > 0 ) {
  3         11  
2113 3         11 while ( $count != 0 ) {
2114 5 100       18 if ( $count > 0 ) {
    50          
2115 3         11 $new_ary->push( $new_ary->shift );
2116 3         10 $count--;
2117             }
2118             elsif ( $count < 0 ) {
2119 2         9 $new_ary->unshift( $new_ary->pop );
2120 2         5 $count++;
2121             }
2122             }
2123             }
2124              
2125 3         17 return $new_ary;
2126             }
2127              
2128             =item rotateEx()
2129             See rotate, but return self inplace.
2130             =cut
2131              
2132             sub rotateEx {
2133 3     3 1 8 my ( $self, $count ) = @_;
2134 3 50       15 ref($self) eq __PACKAGE__ or die;
2135              
2136 3 100       8 $count = 1 if ( not defined $count );
2137              
2138 3 50       4 if ( scalar( @{$self} ) > 0 ) {
  3         16  
2139 3         10 while ( $count != 0 ) {
2140 5 100       17 if ( $count > 0 ) {
    50          
2141 3         11 $self->push( $self->shift );
2142 3         11 $count--;
2143             }
2144             elsif ( $count < 0 ) {
2145 2         8 $self->unshift( $self->pop );
2146 2         5 $count++;
2147             }
2148             }
2149             }
2150              
2151 3         10 return $self;
2152             }
2153              
2154             =item sample()
2155             Chooses a random element or n random elements from the array.
2156            
2157             ra(1, 2, 3, 4)->sample
2158             ra(1, 2, 3, 4)->sample(2)
2159             =cut
2160              
2161             sub sample {
2162 2     2 1 3 my ( $self, $n ) = @_;
2163 2 50       8 ref($self) eq __PACKAGE__ or die;
2164              
2165 2 100       6 if ( defined $n ) {
2166 1 50       4 die 'ArgumentError: negative array size' if ( $n < 0 );
2167              
2168 1         5 my $index_ary = tie my @index_ary, 'Ruby::Collections::Array';
2169 1         7 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
2170              
2171 1     4   12 $self->each_index( sub { $index_ary->push( $_[0] ); } );
  4         11  
2172 1   66     12 for ( my $i = 0 ; $i < $n && scalar(@index_ary) != 0 ; $i++ ) {
2173 4         10 $new_ary->push(
2174 4         13 @{$self}[
2175             $index_ary->delete_at(
2176 4         27 int( rand( scalar( @{$index_ary} ) ) )
2177             )
2178             ]
2179             );
2180             }
2181              
2182 1         6 return $new_ary;
2183             }
2184             else {
2185 1         3 return @{$self}[ int( rand( scalar( @{$self} ) ) ) ];
  1         5  
  1         6  
2186             }
2187             }
2188              
2189             =item select()
2190             Returns a new array which contains all the elements for which the given block returns true.
2191            
2192             ra(1, 4, 6, 7, 8)->select(sub {($_[0]%2) == 0 }) #return ra(4, 6, 8);
2193             =cut
2194              
2195             sub select {
2196 1     1 1 2 my ( $self, $block ) = @_;
2197 1 50       6 ref($self) eq __PACKAGE__ or die;
2198              
2199 1         4 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
2200 1         7 @new_ary = grep { $block->($_) } @{$self};
  5         24  
  1         4  
2201              
2202 1         25 return $new_ary;
2203             }
2204              
2205             *find_all = \&select;
2206              
2207             =item selectEx()
2208             Deleting all the elements from self for which the given block returns false, then returns self.
2209             Alias : keep_if
2210            
2211             ra(1, 4, 6, 7, 8)->selectEx(sub {($_[0]%2) == 0 }) #return ra(4, 6, 8);
2212             =cut
2213              
2214             sub selectEx {
2215 1     1 1 9 my ( $self, $block ) = @_;
2216 1 50       6 ref($self) eq __PACKAGE__ or die;
2217              
2218 1         3 my $before_len = scalar( @{$self} );
  1         3  
2219 1         2 @{$self} = grep { $block->($_) } @{$self};
  1         8  
  5         23  
  1         3  
2220              
2221 1 50       2 if ( scalar( @{$self} ) == $before_len ) {
  1         5  
2222 0         0 return undef;
2223             }
2224             else {
2225 1         4 return $self;
2226             }
2227             }
2228              
2229             =item shift()
2230             Removes the first element of self and returns it.
2231             If a number n is given, then removes the first n element of self and returns them as an array.
2232            
2233             ra(1, 2, 3)->shift #returns 1;
2234             ra(1, 2, 3, 4, 5)->shift(3) #returns ra(1, 2, 3);
2235             =cut
2236              
2237             sub shift {
2238 8     8 1 24 my ( $self, $n ) = @_;
2239 8 50       27 ref($self) eq __PACKAGE__ or die;
2240              
2241 8 100       21 if ( defined $n ) {
2242 1 50       4 die 'ArgumentError: negative array size' if ( $n < 0 );
2243              
2244 1         5 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
2245 1   66     12 for ( my $i ; $i < $n && scalar( @{$self} ) != 0 ; $i++ ) {
  3         42  
2246 3         5 push( @new_ary, shift( @{$self} ) );
  3         11  
2247             }
2248 1         9 return $new_ary;
2249             }
2250             else {
2251 7         11 return shift( @{$self} );
  7         33  
2252             }
2253             }
2254              
2255             =item unshift()
2256             Adding the objects to the front of self.
2257            
2258             ra(2, 4, 6)->unshift(1, 3, 5) #returns ra(1, 3, 5, 2, 4 ,6);
2259             =cut
2260              
2261             sub unshift {
2262 5     5 1 10 my $self = shift @_;
2263 5 50       17 ref($self) eq __PACKAGE__ or die;
2264              
2265 5         7 unshift( @{$self}, @_ );
  5         14  
2266              
2267 5         14 return $self;
2268             }
2269              
2270             =item shuffle()
2271             Returns a new array with all elements of self shuffled.
2272            
2273             ra(1, 2, 3, 4, 5, 6)->shuffle
2274             =cut
2275              
2276             sub shuffle {
2277 1     1 1 6 my ($self) = @_;
2278 1 50       7 ref($self) eq __PACKAGE__ or die;
2279              
2280 1         6 my $index_ary = tie my @index_ary, 'Ruby::Collections::Array';
2281 1         9 my $shuffle_ary = tie my @shuffle_ary, 'Ruby::Collections::Array';
2282 1         8 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
2283              
2284 1     6   13 $self->each_index( sub { $index_ary->push( $_[0] ); } );
  6         15  
2285 1         7 while ( scalar(@index_ary) != 0 ) {
2286 6         38 $shuffle_ary->push(
2287             $index_ary->delete_at( int( rand( scalar(@index_ary) ) ) ) );
2288             }
2289 1         8 for my $i (@shuffle_ary) {
2290 6         29 $new_ary->push( @{$self}[$i] );
  6         17  
2291             }
2292              
2293 1         9 return $new_ary;
2294             }
2295              
2296             =item shuffleEx()
2297             Shuffles all elements in self in place.
2298            
2299             ra(1, 2, 3, 4, 5, 6)->shuffleEx
2300             =cut
2301              
2302             sub shuffleEx {
2303 1     1 1 7 my ($self) = @_;
2304 1 50       6 ref($self) eq __PACKAGE__ or die;
2305              
2306 1         4 my $index_ary = tie my @index_ary, 'Ruby::Collections::Array';
2307 1         7 my $shuffle_ary = tie my @shuffle_ary, 'Ruby::Collections::Array';
2308 1         7 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
2309              
2310 1     6   11 $self->each_index( sub { $index_ary->push( $_[0] ); } );
  6         14  
2311 1         7 while ( scalar(@index_ary) != 0 ) {
2312 6         43 $shuffle_ary->push(
2313             $index_ary->delete_at( int( rand( scalar(@index_ary) ) ) ) );
2314             }
2315 1         8 for my $i (@shuffle_ary) {
2316 6         44 $new_ary->push( @{$self}[$i] );
  6         18  
2317             }
2318 1         8 @{$self} = @new_ary;
  1         8  
2319              
2320 1         21 return $self;
2321             }
2322              
2323             =item slice()
2324             Returns the element at given index.
2325             If the start and length(n) are given, then returns a new array contains the elements
2326             from the start index to following n-1 elements.
2327            
2328             ra(1, 2, 3)->slice(2) #returns 3;
2329             ra(1, 2, 3, 4, 5)->slice(1, 2) #returns ra(2, 3);
2330             =cut
2331              
2332             sub slice {
2333 2     2 1 6 my ( $self, $index, $length ) = @_;
2334 2 50       9 ref($self) eq __PACKAGE__ or die;
2335              
2336 2 100       6 if ( defined $length ) {
2337 1 50 33     2 if ( $index < -scalar( @{$self} ) || $index >= scalar( @{$self} ) ) {
  1         7  
  1         7  
2338 0         0 return undef;
2339             }
2340 1         6 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
2341 1         6 @new_ary = splice( @{$self}, $index, $length );
  1         20  
2342 1         56 return $new_ary;
2343             }
2344             else {
2345 1         5 return $self->at($index);
2346             }
2347             }
2348              
2349             =item sliceEx()
2350             Deleting the element at given index from self, then return this element.
2351             Or deleting the elements from given start index to following n-1 elements from self, then return these elements.
2352            
2353             ra(1, 2, 3)->slice(2) #returns 3;
2354             ra(1, 2, 3, 4, 5)->slice(1, 2) #returns ra(2, 3);
2355             =cut
2356              
2357             sub sliceEx {
2358 2     2 1 12 my ( $self, $index, $length ) = @_;
2359 2 50       12 ref($self) eq __PACKAGE__ or die;
2360              
2361 2 100       9 if ( defined $length ) {
2362 1 50 33     2 if ( $index < -scalar( @{$self} ) || $index >= scalar( @{$self} ) ) {
  1         38  
  1         7  
2363 0         0 return undef;
2364             }
2365 1 50       18 $index += scalar( @{$self} ) if ( $index < 0 );
  0         0  
2366              
2367 1         6 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
2368 1   66     8 for ( my $i = $index ; $i < scalar( @{$self} ) && $length > 0 ; ) {
  3         17  
2369 2         8 $new_ary->push( $self->delete_at($i) );
2370 2         3 $length--;
2371             }
2372              
2373 1         5 return $new_ary;
2374             }
2375             else {
2376 1         5 return $self->delete_at($index);
2377             }
2378             }
2379              
2380             =item slice_before()
2381             Creates a new array for each chuncked elements, the method of chunks could by pattern or block.
2382            
2383             ra(1, 2, 3, 4, 5, 3)->slice_before(3) #returns ra(ra(1, 2), ra(3, 4, 5),ra(3));
2384             ra(1, 2, 3, 4, 5, 3)->slice_before(sub {$_[0]%3 == 0}) #returns ra(ra(1, 2), ra(3, 4, 5),ra(3));
2385             =cut
2386              
2387             sub slice_before {
2388 2     2 1 5 my $self = shift @_;
2389 2 50       8 ref($self) eq __PACKAGE__ or die;
2390              
2391 2         8 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
2392 2         10 my $group = undef;
2393 2 100       9 if ( ref( @_[0] ) eq 'CODE' ) {
2394 1         4 my $block = shift @_;
2395              
2396 1         1 for my $item ( @{$self} ) {
  1         4  
2397 6 100       32 if ( not defined $group ) {
    100          
2398 1         6 $group = tie my @group, 'Ruby::Collections::Array';
2399 1         7 push( @group, $item );
2400             }
2401             elsif ( $block->($item) ) {
2402 2         10 push( @new_ary, $group );
2403 2         17 $group = tie my @group, 'Ruby::Collections::Array';
2404 2         19 push( @group, $item );
2405             }
2406             else {
2407 3         12 push( @{$group}, $item );
  3         7  
2408             }
2409             }
2410             }
2411             else {
2412 1         3 my $pattern = shift @_;
2413              
2414 1         3 for my $item ( @{$self} ) {
  1         2  
2415 6 100       34 if ( not defined $group ) {
    100          
2416 1         5 $group = tie my @group, 'Ruby::Collections::Array';
2417 1         8 push( @group, $item );
2418             }
2419             elsif ( p_obj($item) =~ $pattern ) {
2420 2         6 push( @new_ary, $group );
2421 2         14 $group = tie my @group, 'Ruby::Collections::Array';
2422 2         12 push( @group, $item );
2423             }
2424             else {
2425 3         5 push( @{$group}, $item );
  3         10  
2426             }
2427             }
2428             }
2429 2 50 33     24 if ( defined $group && $group->has_any ) {
2430 2         7 push( @new_ary, $group );
2431             }
2432              
2433 2         18 return $new_ary;
2434             }
2435              
2436             =item sort()
2437             Returns a new array by sorting self.
2438            
2439             ra(1, 3, 5, 2, 7, 0)->sort #returns ra(0, 1, 2, 3, 5, 7);
2440             ra('djh', 'kdirhf', 'a')->sort(sub {length($_[0]) <=> length($_[1])}) #returns ra('a', 'djh', 'kdirhf');
2441             =cut
2442              
2443             sub sort {
2444 30     30 1 68 my ( $self, $block ) = @_;
2445 30 50       87 ref($self) eq __PACKAGE__ or die;
2446              
2447 30         110 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
2448 30 100       163 if ( defined $block ) {
2449 7         13 @new_ary = sort { $block->( $a, $b ) } @{$self};
  15         80  
  7         33  
2450             }
2451             else {
2452             @new_ary = sort {
2453 63 100 66     243 if ( looks_like_number( p_obj($a) )
  23         71  
2454             && looks_like_number( p_obj($b) ) )
2455             {
2456 32         74 p_obj($a) <=> p_obj($b);
2457             }
2458             else {
2459 31         83 p_obj($a) cmp p_obj($b);
2460             }
2461 23         29 } @{$self};
2462             }
2463              
2464 30         674 return $new_ary;
2465             }
2466              
2467             =item sortEx()
2468             Sorts self in place.
2469            
2470             ra(1, 3, 5, 2, 7, 0)->sortEx #returns ra(0, 1, 2, 3, 5, 7);
2471             ra('djh', 'kdirhf', 'a')->sortEx(sub {length($_[0]) <=> length($_[1])}) #returns ra('a', 'djh', 'kdirhf');
2472             =cut
2473              
2474             sub sortEx {
2475 2     2 1 19 my ( $self, $block ) = @_;
2476 2 50       9 ref($self) eq __PACKAGE__ or die;
2477              
2478 2 100       8 if ( defined $block ) {
2479 1         3 @{$self} = sort { $block->( $a, $b ) } @{$self};
  1         7  
  2         10  
  1         7  
2480             }
2481             else {
2482 1         8 @{$self} = sort {
2483 11 50 33     52 if ( looks_like_number( p_obj($a) )
  1         5  
2484             && looks_like_number( p_obj($b) ) )
2485             {
2486 11         29 p_obj($a) <=> p_obj($b);
2487             }
2488             else {
2489 0         0 p_obj($a) cmp p_obj($b);
2490             }
2491 1         2 } @{$self};
2492             }
2493              
2494 2         13 return $self;
2495             }
2496              
2497             =item sort_by()
2498             Returns a new array by sorting self with block method.
2499            
2500             ra(2, 3, 7, 89, 6)->sort_by(sub {$_[0]-2}) #returns ra(2, 3, 6, 7, 89);
2501             =cut
2502              
2503             sub sort_by {
2504 7     7 1 15 my ( $self, $block ) = @_;
2505 7 50       29 ref($self) eq __PACKAGE__ or die;
2506              
2507 7         30 my $trans_ary = tie my @trans_ary, 'Ruby::Collections::Array';
2508 7         37 for my $item ( @{$self} ) {
  7         17  
2509 23         189 push( @trans_ary, [ $block->($item), $item ] );
2510             }
2511 25         88 @trans_ary = sort {
2512 7 50 33     85 if ( looks_like_number( p_obj( @{$a}[0] ) )
  25         127  
  25         81  
2513             && looks_like_number( p_obj( @{$b}[0] ) ) )
2514             {
2515 25         37 p_obj( @{$a}[0] ) <=> p_obj( @{$b}[0] );
  25         80  
  25         81  
2516             }
2517             else {
2518 0         0 p_obj( @{$a}[0] ) cmp p_obj( @{$b}[0] );
  0         0  
  0         0  
2519             }
2520             } @trans_ary;
2521 7     23   181 $trans_ary->mapEx( sub { return @{ $_[0] }[1]; } );
  23         31  
  23         66  
2522              
2523 7         76 return $trans_ary;
2524             }
2525              
2526             =item sort_byEx()
2527             Sorting self with block method, and return self.
2528            
2529             ra(2, 3, 7, 89, 6)->sort_byEx(sub {$_[0]-2}) #returns ra(2, 3, 6, 7, 89);
2530             =cut
2531              
2532             sub sort_byEx {
2533 1     1 1 10 my ( $self, $block ) = @_;
2534 1 50       6 ref($self) eq __PACKAGE__ or die;
2535              
2536 1         5 my $trans_ary = tie my @trans_ary, 'Ruby::Collections::Array';
2537 1         7 for my $item ( @{$self} ) {
  1         4  
2538 5         38 push( @trans_ary, [ $block->($item), $item ] );
2539             }
2540 7         27 @trans_ary = sort {
2541 1 50 33     12 if ( looks_like_number( p_obj( @{$a}[0] ) )
  7         33  
  7         34  
2542             && looks_like_number( p_obj( @{$b}[0] ) ) )
2543             {
2544 7         10 p_obj( @{$a}[0] ) <=> p_obj( @{$b}[0] );
  7         26  
  7         30  
2545             }
2546             else {
2547 0         0 p_obj( @{$a}[0] ) cmp p_obj( @{$b}[0] );
  0         0  
  0         0  
2548             }
2549             } @trans_ary;
2550 1     5   45 $trans_ary->mapEx( sub { return @{ $_[0] }[1]; } );
  5         8  
  5         17  
2551 1         8 @{$self} = @trans_ary;
  1         10  
2552              
2553 1         43 return $self;
2554             }
2555              
2556             =item take()
2557             Takes the first n elements from the array.
2558            
2559             ra(3, 5, 6, 7, 8, 9)->take(2) #returns ra(3, 5);
2560             =cut
2561              
2562             sub take {
2563 1     1 1 4 my ( $self, $n ) = @_;
2564 1 50       5 ref($self) eq __PACKAGE__ or die;
2565              
2566 1 50       5 if ( defined $n ) {
2567 1 50       5 die 'ArgumentError: negative array size' if ( $n < 0 );
2568              
2569 1         5 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
2570 1   66     13 for ( my $i ; $i < $n && $i < scalar( @{$self} ) ; $i++ ) {
  2         17  
2571 2         3 push( @new_ary, @{$self}[$i] );
  2         10  
2572             }
2573 1         12 return $new_ary;
2574             }
2575             else {
2576 0         0 die 'ArgumentError: wrong number of arguments (0 for 1)';
2577             }
2578             }
2579              
2580             =item take_while()
2581             Passes all elements to the block until the block is false, then returns the previous elements.
2582            
2583             ra(2, 4, 3 ,6 ,7 , 8, 2)->take_while(sub {$_[0] < 5}) #returns ra(2, 4, 3);
2584             =cut
2585              
2586             sub take_while {
2587 1     1 1 3 my ( $self, $block ) = @_;
2588 1 50       6 ref($self) eq __PACKAGE__ or die;
2589              
2590 1         5 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
2591 1         8 for my $item ( @{$self} ) {
  1         3  
2592 4 100       22 if ( $block->($item) ) {
2593 3         17 push( @new_ary, $item );
2594             }
2595             else {
2596 1         9 return $new_ary;
2597             }
2598             }
2599              
2600 0         0 return $new_ary;
2601             }
2602              
2603             =item to_a()
2604             Returns self.
2605            
2606             ra(2, 4, 6, 7, 8, 9)->to_a #returns ra(2, 4, 6, 7, 8, 9);
2607             =cut
2608              
2609             sub to_a {
2610 2     2 1 4 my ( $self, $block ) = @_;
2611 2 50       9 ref($self) eq __PACKAGE__ or die;
2612              
2613 2         10 return $self;
2614             }
2615              
2616 0     0 0 0 sub transpose {
2617            
2618             }
2619              
2620             =item entries()
2621             Returns an array containing all elements.
2622            
2623             rh(2=>4, 4=>5, 6=>7)->entries #returns ra(ra(2, 4),ra(4, 5) ,ra(6, 7));
2624             =cut
2625              
2626             sub entries {
2627 0     0 1 0 my ( $self, $block ) = @_;
2628 0 0       0 ref($self) eq __PACKAGE__ or die;
2629              
2630 0         0 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
2631 0         0 @new_ary = @{$self};
  0         0  
2632              
2633 0         0 return @new_ary;
2634             }
2635              
2636             =item zip()
2637             Converts all arguments into array, and merges each arrays with self by corresponding index.
2638            
2639             my $a = ra(1, 2, 3);
2640             my $b = ra(4, 5, 6);
2641             my $c = ra(7, 8);
2642             $a->zip($b) #returns ra(ra(1, 4), ra(2, 5), ra(3, 6));
2643             $a->zip($c) #returns ra(ra(1, 7), ra(2, 8), ra(3, undef));
2644             =cut
2645              
2646             sub zip {
2647 5     5 1 28 my ($self) = @_;
2648 5 50       21 ref($self) eq __PACKAGE__ or die;
2649 5         10 my $block = undef;
2650 5 50       17 $block = pop @_ if ( ref( $_[-1] ) eq 'CODE' );
2651              
2652 5         23 my $new_ary = tie my @new_ary, 'Ruby::Collections::Array';
2653 5         36 for ( my $i = 0 ; $i < scalar( @{$self} ) ; $i++ ) {
  18         99  
2654 13         51 my $zip = tie my @zip, 'Ruby::Collections::Array';
2655 13         73 for my $ary (@_) {
2656 26         93 push( @zip, @{$ary}[$i] );
  26         87  
2657             }
2658 13 50       84 if ( defined $block ) {
2659 0         0 $block->($zip);
2660             }
2661             else {
2662 13         34 push( @new_ary, $zip );
2663             }
2664             }
2665              
2666 5 50       18 if ( defined $block ) {
2667 0         0 return undef;
2668             }
2669             else {
2670 5         35 return $new_ary;
2671             }
2672             }
2673              
2674             =item union()
2675             Returns a new array by joining with given array, and removing the duplicate elements.
2676            
2677             ra(1, 3, 4)->union(ra(2, 4, 6)) #returns ra(1, 3, 4, 2, 6);
2678             =cut
2679              
2680             sub union {
2681 1     1 1 3 my ( $self, $other ) = @_;
2682 1 50       5 ref($self) eq __PACKAGE__ or die;
2683              
2684 1         6 my $union = tie my @union, 'Ruby::Collections::Array';
2685 1         7 foreach my $item ( @{$self} ) {
  1         3  
2686 3 50       18 if ( not $union->include($item) ) {
2687 3         10 push( @union, $item );
2688             }
2689             }
2690 1         7 foreach my $item ( @{$other} ) {
  1         4  
2691 3 100       12 if ( not $union->include($item) ) {
2692 2         6 push( @union, $item );
2693             }
2694             }
2695              
2696 1         16 return $union;
2697             }
2698              
2699             if ( __FILE__ eq $0 ) {
2700             my $ref = [ 1, 2, 3, 4, 5, 11 ];
2701             p ra($ref)->map( sub { $_[0] * 2 } )->minmax;
2702             }
2703              
2704             1;
2705             __END__;