File Coverage

blib/lib/LINQ/Collection.pm
Criterion Covered Total %
statement 356 359 99.1
branch 141 144 99.3
condition 19 21 90.4
subroutine 72 74 97.3
pod 47 47 100.0
total 635 645 98.7


line stmt bran cond sub pod time code
1 115     115   69077 use 5.006;
  115         404  
2 115     115   603 use strict;
  115         222  
  115         2398  
3 115     115   530 use warnings;
  115         208  
  115         6163  
4              
5             package LINQ::Collection;
6              
7             our $AUTHORITY = 'cpan:TOBYINK';
8             our $VERSION = '0.002';
9              
10 115     115   1128 use Role::Tiny;
  115         261  
  115         695  
11 115     115   43457 use LINQ::Util::Internal ();
  115         265  
  115         556499  
12              
13             requires qw( to_list );
14              
15             my $_coerce = sub {
16             my ( $thing ) = @_;
17            
18             require Scalar::Util;
19             if ( Scalar::Util::blessed( $thing ) and $thing->DOES( __PACKAGE__ ) ) {
20             return $thing;
21             }
22            
23             if ( ref( $thing ) eq 'ARRAY' ) {
24             require LINQ::Array;
25             return LINQ::Array::->new( $thing );
26             }
27            
28             LINQ::Util::Internal::throw(
29             "CallerError",
30             message => "Expected a LINQ collection; got '$thing'"
31             );
32             };
33              
34             sub select {
35 80     80 1 269 my $self = shift;
36 80         233 my $map = LINQ::Util::Internal::assert_code( @_ );
37            
38 80         239 my $iter = $self->to_iterator;
39 80         165 my $stopped;
40            
41 80         381 require LINQ;
42             LINQ::LINQ(
43             sub {
44             # uncoverable branch true
45 446 50   446   756 return LINQ::END() if $stopped;
46 446         742 my @got = $iter->();
47 446 100       916 if ( @got ) {
48 366         531 local $_;
49 366         961 return scalar $map->( $_ = $got[0] );
50             }
51 80         174 ++$stopped;
52 80         263 return LINQ::END();
53             }
54 80         423 );
55             } #/ sub select
56              
57             sub where {
58 159     159 1 621 my $self = shift;
59 159         545 my $filter = LINQ::Util::Internal::assert_code( @_ );
60            
61 159         445 my $iter = $self->to_iterator;
62 159         267 my $stopped;
63            
64 159         801 require LINQ;
65             LINQ::LINQ(
66             sub {
67             GETVAL: {
68 418 100   418   577 return LINQ::END() if $stopped;
  1145         1843  
69 1143         1860 my @got = $iter->();
70 1143 100       2042 if ( @got ) {
71 1017         1323 local $_;
72 1017         2998 my $pass = $filter->( $_ = $got[0] );
73 1004 100       11141 return $got[0] if $pass;
74 727         1226 redo GETVAL;
75             }
76 126         259 ++$stopped;
77 126         381 return LINQ::END();
78             } #/ GETVAL:
79             }
80 159         940 );
81             } #/ sub where
82              
83             sub select_many {
84 4     4 1 22 my $self = shift;
85 4         11 my $map = LINQ::Util::Internal::assert_code( @_ );
86            
87 4         11 my $outer = $self->to_iterator;
88 4         7 my $inner;
89             my $end;
90            
91 4         20 require LINQ;
92             LINQ::LINQ(
93             sub {
94             BODY: {
95 28 100   28   28 return LINQ::END() if $end;
  56         87  
96 52 100       91 if ( not $inner ) {
97 28         63 $inner = $outer->();
98 28 100       47 if ( defined $inner ) {
99 24         36 local $_;
100 24         50 $inner = $map->( $_ = $inner )->$_coerce->to_iterator;
101             }
102             else {
103 4         6 $end = 1;
104 4         6 redo BODY;
105             }
106             } #/ if ( not $inner )
107 48         88 my @got = $inner->();
108 48 100       74 if ( not @got ) {
109 24         57 undef $inner;
110 24         36 redo BODY;
111             }
112 24         56 return @got;
113             } #/ BODY:
114             }
115 4         30 );
116             } #/ sub select_many
117              
118             sub min {
119 6     6 1 13 my $self = shift;
120 6 100       21 return $self->select( @_ )->min if @_;
121 4         23 require List::Util;
122 4         11 &List::Util::min( $self->to_list );
123             }
124              
125             sub max {
126 6     6 1 8 my $self = shift;
127 6 100       19 return $self->select( @_ )->max if @_;
128 4         25 require List::Util;
129 4         10 &List::Util::max( $self->to_list );
130             }
131              
132             sub sum {
133 12     12 1 26 my $self = shift;
134 12 100       47 return $self->select( @_ )->sum if @_;
135 8         68 require List::Util;
136 8         35 &List::Util::sum( $self->to_list );
137             }
138              
139             sub average {
140 4     4 1 10 my $self = shift;
141 4         15 $self->sum( @_ ) / $self->count();
142             }
143              
144             sub aggregate {
145 5     5 1 11 my $self = shift;
146 5         19 my $code = LINQ::Util::Internal::assert_code( shift );
147 5     11   20 my $wrapper = sub { $code->( $a, $b ) };
  11         77  
148 5         38 require List::Util;
149 5         24 &List::Util::reduce( $wrapper, @_, $self->to_list );
150             }
151              
152             my $_prepare_join = sub {
153             my $x = shift;
154             my $y = shift;
155            
156             my $hint = ref( $_[0] ) ? -inner : shift( @_ );
157             my $x_keys = LINQ::Util::Internal::assert_code( shift );
158             my $y_keys = LINQ::Util::Internal::assert_code( shift );
159             my $joiner = LINQ::Util::Internal::assert_code( @_ );
160            
161             $hint =~ /\A-(inner|left|right|outer)\z/
162             or LINQ::Util::Internal::throw(
163             "CallerError",
164             message => "Expected a recognized join type; got '$hint'"
165             );
166            
167             my @x_mapped =
168             $x->select( sub { [ scalar( $x_keys->( $_[0] ) ), $_[0] ] } )->to_list;
169             my @y_mapped =
170             $y->select( sub { [ scalar( $y_keys->( $_[0] ) ), $_[0] ] } )->to_list;
171            
172             return ( \@x_mapped, \@y_mapped, $hint, $joiner );
173             };
174              
175             sub join {
176 13     13 1 54 my ( $x_mapped, $y_mapped, $hint, $joiner ) = $_prepare_join->( @_ );
177            
178 13         28 my @joined;
179 13         20 my ( @found_x, @found_y );
180            
181 13         51 for my $Xi ( 0 .. $#$x_mapped ) {
182 63         93 my $X = $x_mapped->[$Xi];
183            
184 63         108 for my $Yi ( 0 .. $#$y_mapped ) {
185 369         3444 my $Y = $y_mapped->[$Yi];
186            
187 369 100       791 if ( $X->[0] eq $Y->[0] ) {
188 63         87 my $a = $X->[1];
189 63         76 my $b = $Y->[1];
190 63         85 $found_x[$Xi]++;
191 63         93 $found_y[$Yi]++;
192            
193 63         160 push @joined, scalar $joiner->( $a, $b );
194             }
195             } #/ for my $Yi ( 0 .. $#$y_mapped)
196             } #/ for my $Xi ( 0 .. $#$x_mapped)
197            
198 13 100 100     67 if ( $hint eq -left or $hint eq -outer ) {
199 6         16 for my $Xi ( 0 .. $#$x_mapped ) {
200 30 100       325 next if $found_x[$Xi];
201 12         20 my $a = $x_mapped->[$Xi][1];
202 12         19 my $b = undef;
203 12         35 push @joined, scalar $joiner->( $a );
204             }
205             }
206            
207 13 100 100     57 if ( $hint eq -right or $hint eq -outer ) {
208 6         16 for my $Yi ( 0 .. $#$y_mapped ) {
209 36 100       61 next if $found_y[$Yi];
210 6         13 my $a = undef;
211 6         11 my $b = $y_mapped->[$Yi][1];
212 6         14 push @joined, scalar $joiner->( undef, $b );
213             }
214             }
215            
216 13         255 LINQ::Util::Internal::create_linq( \@joined );
217             } #/ sub join
218              
219             sub group_join {
220 9     9 1 47 my ( $x_mapped, $y_mapped, $hint, $joiner ) = $_prepare_join->( @_ );
221            
222 9 100       75 $hint =~ /\A-(left|inner)\z/ or LINQ::Util::Internal::throw(
223             "CallerError",
224             message => "Join type '$hint' not supported for group_join",
225             );
226            
227 5         10 my @joined;
228 5         18 my ( @found_x, @found_y );
229            
230 5         25 for my $Xi ( 0 .. $#$x_mapped ) {
231 23         143 my $X = $x_mapped->[$Xi];
232 23         133 my @group = map $_->[1], grep $X->[0] eq $_->[0], @$y_mapped;
233            
234 23 100 100     76 if ( @group or $hint eq -left ) {
235 19         25 my $a = $X->[1];
236 19         48 my $b = LINQ::Util::Internal::create_linq( \@group );
237 19         42 push @joined, scalar $joiner->( $a, $b );
238             }
239             } #/ for my $Xi ( 0 .. $#$x_mapped)
240            
241 5         40 LINQ::Util::Internal::create_linq( \@joined );
242             } #/ sub group_join
243              
244             sub take {
245 13     13 1 43 my $self = shift;
246 13         24 my ( $n ) = @_;
247 13     66   69 $self->take_while( sub { $n-- > 0 } );
  66         222  
248             }
249              
250             sub take_while {
251 21     21 1 56 my $self = shift;
252 21         55 my $filter = LINQ::Util::Internal::assert_code( @_ );
253 21         38 my $stopped = 0;
254 21         51 my $iter = $self->to_iterator;
255            
256 21         113 require LINQ;
257             LINQ::LINQ(
258             sub {
259             # uncoverable branch true
260 100 50   100   179 return LINQ::END() if $stopped;
261 100         177 my @got = $iter->();
262 98 100 100     333 if ( !@got or !$filter->( $_ = $got[0] ) ) {
263 19         60 $stopped++;
264 19         56 return LINQ::END();
265             }
266 79         234 return $got[0];
267             }
268 21         136 );
269             } #/ sub take_while
270              
271             sub skip {
272 8     8 1 27 my $self = shift;
273 8         14 my ( $n ) = @_;
274 8     24   49 $self->skip_while( sub { $n-- > 0 } );
  24         112  
275             }
276              
277             sub skip_while {
278 14     14 1 43 my $self = shift;
279 14         43 my $filter = LINQ::Util::Internal::assert_code( @_ );
280 14         58 my $stopped = 0;
281 14         20 my $started = 0;
282 14         36 my $iter = $self->to_iterator;
283            
284 14         79 require LINQ;
285             LINQ::LINQ(
286             sub {
287             SKIPPING: {
288 76 100   76   95 return LINQ::END() if $stopped;
  118         207  
289 104         188 my @got = $iter->();
290 104 100       193 if ( !@got ) {
291 14         21 $stopped++;
292 14         20 redo SKIPPING;
293             }
294 90 100       206 return $got[0] if $started;
295 40 100       102 if ( $filter->( $_ = $got[0] ) ) {
296 28         72 redo SKIPPING;
297             }
298 12         43 ++$started;
299 12         42 return $got[0];
300             } #/ SKIPPING:
301             }
302 14         86 );
303             } #/ sub skip_while
304              
305             sub concat {
306 12     12 1 36 my @collections = map $_->to_iterator, @_;
307 12         22 my $idx = 0;
308            
309 12         44 require LINQ;
310             LINQ::LINQ(
311             sub {
312             FIND_NEXT: {
313 100 100   100   118 return LINQ::END() if not @collections;
  121         224  
314            
315 111         219 my @got = $collections[0]->();
316 111 100       200 if ( not @got ) {
317 21         29 shift @collections;
318 21         82 redo FIND_NEXT;
319             }
320            
321 90         259 return $got[0];
322             } #/ FIND_NEXT:
323             }
324 12         56 );
325             } #/ sub concat
326              
327             sub order_by {
328 48     48 1 23772 my $self = shift;
329 48         130 my ( $hint, $keygen ) = ( -numeric, undef );
330 48 100       144 if ( @_ ) {
331 46 100       147 $hint = ref( $_[0] ) ? -numeric : shift( @_ );
332 46 100       197 $keygen = @_ ? LINQ::Util::Internal::assert_code( @_ ) : undef;
333             }
334            
335 48 100       130 if ( not $keygen ) {
336 12 100       54 if ( $hint eq -string ) {
    100          
337             return LINQ::Util::Internal::create_linq(
338 2         11 [ sort { $a cmp $b } $self->to_list ] );
  10         25  
339             }
340             elsif ( $hint eq -numeric ) {
341             return LINQ::Util::Internal::create_linq(
342 8         26 [ sort { $a <=> $b } $self->to_list ] );
  40         94  
343             }
344             } #/ if ( not $keygen )
345            
346 38 100       171 if ( $hint eq -string ) {
    100          
347             return LINQ::Util::Internal::create_linq(
348             [
349             map $_->[1],
350 22         77 sort { $a->[0] cmp $b->[0] }
  165         661  
351             map [ $keygen->( $_ ), $_ ],
352             $self->to_list
353             ]
354             );
355             } #/ if ( $hint eq -string )
356            
357             elsif ( $hint eq -numeric ) {
358             return LINQ::Util::Internal::create_linq(
359             [
360             map $_->[1],
361 14         47 sort { $a->[0] <=> $b->[0] }
  86         539  
362             map [ $keygen->( $_ ), $_ ],
363             $self->to_list
364             ]
365             );
366             } #/ elsif ( $hint eq -numeric)
367            
368             LINQ::Util::Internal::throw(
369 2         18 "CallerError",
370             message => "Expected '-numeric' or '-string'; got '$hint'"
371             );
372             } #/ sub order_by
373              
374             sub then_by {
375 2     2 1 8 LINQ::Util::Internal::throw( "Unimplemented", method => "then_by" );
376             }
377              
378             sub order_by_descending {
379 6     6 1 26 my $self = shift;
380 6         15 $self->order_by( @_ )->reverse;
381             }
382              
383             sub then_by_descending {
384 2     2 1 7 LINQ::Util::Internal::throw( "Unimplemented", method => "then_by_descending" );
385             }
386              
387             sub reverse {
388 8     8 1 23 my $self = shift;
389 8         22 LINQ::Util::Internal::create_linq(
390             [ reverse( $self->to_list ) ],
391             );
392             }
393              
394             sub group_by {
395 2     2 1 21 my $self = shift;
396 2         8 my $keygen = LINQ::Util::Internal::assert_code( @_ );
397            
398 2         5 my @keys;
399             my %values;
400            
401 2         9 for ( $self->to_list ) {
402 20         35 my $key = $keygen->( $_ );
403 20 100       70 unless ( $values{$key} ) {
404 6         18 push @keys, $key;
405 6         15 $values{$key} = [];
406             }
407 20         23 push @{ $values{$key} }, $_;
  20         31  
408             }
409            
410 2         1312 require LINQ::Grouping;
411             LINQ::Util::Internal::create_linq(
412             [
413             map 'LINQ::Grouping'->new(
414             key => $_,
415 2         22 values => LINQ::Util::Internal::create_linq( $values{$_} ),
416             ),
417             @keys
418             ]
419             );
420             } #/ sub group_by
421              
422             sub distinct {
423 8     8 1 22 my $self = shift;
424             my $compare =
425 8 100   36   84 @_ ? LINQ::Util::Internal::assert_code( @_ ) : sub { $_[0] == $_[1] };
  36         88  
426            
427 8         13 my @already;
428             $self->where(
429             sub {
430 46     46   59 my $maybe = $_[0];
431 46         76 for my $got ( @already ) {
432 86 100       241 return !!0 if $compare->( $maybe, $got );
433             }
434 34         165 push @already, $maybe;
435 34         61 return !!1;
436             }
437 8         34 );
438             } #/ sub distinct
439              
440             sub union {
441 4     4 1 18 my $self = shift;
442 4         9 my ( $other, @compare ) = @_;
443 4         14 $self->concat( $other )->distinct( @compare );
444             }
445              
446             sub intersect {
447 4     4 1 18 my $self = shift;
448 4         6 my $other = shift;
449             my @compare =
450 4 100   12   16 @_ ? LINQ::Util::Internal::assert_code( @_ ) : sub { $_[0] == $_[1] };
  12         25  
451 4     10   26 $self->where( sub { $other->contains( $_, @compare ) } );
  10         34  
452             }
453              
454             sub except {
455 4     4 1 20 my $self = shift;
456 4         6 my $other = shift;
457             my @compare =
458 4 100   12   21 @_ ? LINQ::Util::Internal::assert_code( @_ ) : sub { $_[0] == $_[1] };
  12         21  
459 4     10   36 $self->where( sub { not $other->contains( $_, @compare ) } );
  10         32  
460             }
461              
462             sub sequence_equal {
463 18     18 1 57 my $self = shift;
464 18         124 my ( $other, @compare ) = @_;
465            
466 18         19 my $compare;
467 18 100       46 if ( @compare ) {
468 12         32 $compare = LINQ::Util::Internal::assert_code( @compare );
469             }
470            
471 18         41 my $iter1 = $self->to_iterator;
472 18         34 my $iter2 = $other->to_iterator;
473            
474 18         28 while ( 1 ) {
475 114         286 my @got1 = $iter1->();
476 114         161 my @got2 = $iter2->();
477            
478 114 100       210 if ( not @got1 ) {
    100          
479 10 100       19 if ( @got2 ) {
480 4         28 return !!0;
481             }
482             else {
483 6         49 return !!1;
484             }
485             }
486             elsif ( not @got2 ) {
487 2         60 return !!0;
488             }
489            
490 102 100       144 if ( $compare ) {
491 60 100       111 return !!0 unless $compare->( $got1[0], $got2[0] );
492             }
493             else {
494 42 100       87 return !!0 unless $got1[0] == $got2[0];
495             }
496             } #/ while ( 1 )
497             } #/ sub sequence_equal
498              
499             my $_with_default = sub {
500             my $self = shift;
501             my $method = shift;
502             my @args = @_;
503             my $default = pop( @args );
504            
505             my $return;
506             eval { $return = $self->$method( @args ); 1 } or do {
507             my $e = $@; # catch
508            
509             # Rethrow any non-blessed errors.
510             require Scalar::Util;
511             die( $e ) unless Scalar::Util::blessed( $e );
512            
513             # Rethrow any errors of the wrong class.
514             die( $e )
515             unless $e->isa( 'LINQ::Exception::NotFound' )
516             || $e->isa( 'LINQ::Exception::MultipleFound' );
517            
518             # Rethrow any errors which resulted from the wrong source.
519             die( $e ) unless $e->collection == $self;
520            
521             return $default;
522             };
523            
524             return $return;
525             };
526              
527             sub first {
528 13     13 1 25 my $self = shift;
529 13 100       57 my $found = @_ ? $self->where( @_ ) : $self;
530 13 100       47 return $found->element_at( 0 ) if $found->count > 0;
531 4         19 LINQ::Util::Internal::throw( 'NotFound', collection => $self );
532             }
533              
534             sub first_or_default {
535 6     6 1 153 shift->$_with_default( first => @_ );
536             }
537              
538             sub last {
539 13     13 1 38 my $self = shift;
540 13 100       62 my $found = @_ ? $self->where( @_ ) : $self;
541 13 100       45 return $found->element_at( -1 ) if $found->count > 0;
542 4         19 LINQ::Util::Internal::throw( 'NotFound', collection => $self );
543             }
544              
545             sub last_or_default {
546 6     6 1 157 shift->$_with_default( last => @_ );
547             }
548              
549             sub single {
550 32     32 1 381 my $self = shift;
551 32 100       136 my $found = @_ ? $self->where( @_ ) : $self;
552 32 100       93 return $found->element_at( 0 ) if $found->count == 1;
553 8 100       26 $found->count == 0
554             ? LINQ::Util::Internal::throw( 'NotFound', collection => $self )
555             : LINQ::Util::Internal::throw( 'MultipleFound', collection => $self,
556             found => $found );
557             }
558              
559             sub single_or_default {
560 8     8 1 236 shift->$_with_default( single => @_ );
561             }
562              
563             sub element_at {
564 60     60 1 111 my $self = shift;
565 60         101 my ( $i ) = @_;
566            
567 60         171 my @list = $self->to_list;
568            
569 60 100       167 if ( $i > $#list ) {
570 2         7 LINQ::Util::Internal::throw( 'NotFound', collection => $self );
571             }
572            
573 58 100       164 if ( $i < 0 - @list ) {
574 2         7 LINQ::Util::Internal::throw( 'NotFound', collection => $self );
575             }
576            
577 56         481 $list[$i];
578             } #/ sub element_at
579              
580             sub element_at_or_default {
581 24     24 1 56 shift->$_with_default( element_at => @_ );
582             }
583              
584             sub any {
585 32     32 1 50 my $self = shift;
586 32 100       106 my $iter = @_ ? $self->where( @_ )->to_iterator : $self->to_iterator;
587 32         146 my @got = $iter->();
588 32         343 !!scalar @got;
589             }
590              
591             sub all {
592 8     8 1 34 my $self = shift;
593 8         22 my $check = LINQ::Util::Internal::assert_code( @_ );
594 8     15   35 my $iter = $self->where( sub { not $check->( $_ ) } )->to_iterator;
  15         72  
595 8         42 my @got = $iter->();
596 8         134 !scalar @got;
597             }
598              
599             sub contains {
600 31     31 1 61 my $self = shift;
601 31         66 my ( $x, @args ) = @_;
602            
603 31 100       66 if ( @args ) {
604 24         44 splice( @args, 1, 0, $x );
605 24         64 return $self->any( LINQ::Util::Internal::assert_code( @args ) );
606             }
607            
608 7         33 my $iter = $self->to_iterator;
609 7         14 while ( 1 ) {
610 187 100       299 my @got = $iter->() or return !!0;
611 184 100       363 return !!1 if $got[0] == $x;
612             }
613             } #/ sub contains
614              
615             sub count {
616 98     98 1 353 my $self = shift;
617 98 100       242 return $self->where( @_ )->count if @_;
618 97         268 my @list = $self->to_list;
619 91         513 return scalar( @list );
620             }
621              
622             sub to_array {
623 61     61 1 20005 my $self = shift;
624 61         148 [ $self->to_list ];
625             }
626              
627             sub to_dictionary {
628 4     4 1 8 my $self = shift;
629 4         13 my ( $keygen ) = LINQ::Util::Internal::assert_code( @_ );
630 4         13 +{ map +( $keygen->( $_ ), $_ ), $self->to_list };
631             }
632              
633             sub to_lookup {
634 2     2 1 5 my $self = shift;
635 2         4 $self->to_dictionary( @_ );
636             }
637              
638             sub to_iterator {
639 192     192 1 287 my $self = shift;
640 192         545 my @list = $self->to_list;
641 192 100   1056   668 sub { @list ? shift( @list ) : () };
  1056         2143  
642             }
643              
644             sub cast {
645 6     6 1 57684 my $self = shift;
646 6         17 my ( $type ) = @_;
647            
648 6         35 my $cast = $self->of_type( @_ );
649 6 100       26 return $cast if $self->count == $cast->count;
650            
651 4         19 LINQ::Util::Internal::throw( "Cast", collection => $self, type => $type );
652             }
653              
654             sub of_type {
655 22     22 1 6162 my $self = shift;
656 22         45 my ( $type ) = @_;
657            
658 22         148 require Scalar::Util;
659            
660 22 100 100     198 unless ( Scalar::Util::blessed( $type ) and $type->can( 'check' ) ) {
661 8         56 LINQ::Util::Internal::throw(
662             "CallerError",
663             message => "Expected type constraint; got '$type'",
664             );
665             }
666            
667 14 100       211 if ( $type->isa( 'Type::Tiny' ) ) {
668 10         150 my $check = $type->compiled_check;
669            
670 10 100       237 if ( $type->has_coercion ) {
671 6         87 my $coercion = $type->coercion->compiled_coercion;
672 6         5856 return $self->select( $coercion )->where( $check );
673             }
674            
675 4         203 return $self->where( $check );
676             } #/ if ( $type->isa( 'Type::Tiny'...))
677            
678 4 50 33     33 if ( $type->can( 'has_coercion' ) and $type->has_coercion ) {
679             return $self
680 0     0   0 ->select( sub { $type->coerce( $_ ) } )
681 0     0   0 ->where( sub { $type->check( $_ ) } );
  0         0  
682             }
683            
684 4     36   24 return $self->where( sub { $type->check( $_ ) } );
  36         70  
685             } #/ sub of_type
686              
687             sub zip {
688 4     4 1 24 my $self = shift;
689 4         6 my $other = shift;
690 4         11 my $map = LINQ::Util::Internal::assert_code( @_ );
691            
692 4         14 my $iter1 = $self->to_iterator;
693 4         10 my $iter2 = $other->to_iterator;
694 4         9 my @results;
695            
696 4         18 require LINQ;
697             LINQ::LINQ(
698             sub {
699 44     44   74 my @r1 = $iter1->();
700 44         73 my @r2 = $iter2->();
701 44 100 100     130 return LINQ::END() unless @r1 && @r2;
702 40         85 $map->( $r1[0], $r2[0] );
703             }
704 4         34 );
705             } #/ sub zip
706              
707             sub default_if_empty {
708 4     4 1 20 my $self = shift;
709 4         7 my $item = shift;
710            
711 4 100       9 if ( $self->count == 0 ) {
712 2         8 return LINQ::Util::Internal::create_linq( [$item] );
713             }
714            
715 2         7 return $self;
716             } #/ sub default_if_empty
717              
718             sub foreach {
719 9     9 1 5364 my $self = shift;
720 9         56 my $code = LINQ::Util::Internal::assert_code( @_ );
721            
722 9         20 my $ok = eval {
723 9         17 local $LINQ::IN_LOOP = 1;
724 9     234   39 $self->where( sub { $code->( $_ ); 0 } )->to_list;
  234         403  
  227         544  
725 2         20 1;
726             };
727 9 100       131 if ( not $ok ) {
728 7         13 my $e = $@;
729 7         36 require Scalar::Util;
730 7 100       42 die( $e ) unless Scalar::Util::blessed( $e );
731 5 100       65 die( $e ) unless $e->isa( 'LINQ::LAST' );
732             }
733 5         15 return;
734             } #/ sub foreach
735              
736             1;
737              
738             __END__
739              
740             =pod
741              
742             =encoding utf-8
743              
744             =head1 NAME
745              
746             LINQ - the interface which all LINQ collections share
747              
748             =head1 SYNOPSIS
749              
750             use feature 'say';
751             use LINQ 'LINQ';
752            
753             my $double_even_numbers =
754             LINQ( [1..100] )
755             ->where( sub { $_ % 2 == 0 } )
756             ->select( sub { $_ * 2 } );
757            
758             if ( not $double_even_numbers->DOES( 'LINQ::Collection' ) ) {
759             die "What? But you said they all do it!";
760             }
761            
762             for my $n ( $double_even_numbers->to_list ) {
763             say $n;
764             }
765              
766             =head1 DESCRIPTION
767              
768             Objects returned by the C<< LINQ() >>, C<< LINQ::Repeat() >>, and
769             C<< LINQ::Range() >> functions all provide the LINQ::Collection interface.
770             Many of the methods in this interface also return new objects which provide
771             this interface.
772              
773             =head1 METHODS
774              
775             Many methods take a parameter "CALLABLE". This means they can accept a
776             coderef, an object overloading C<< &{} >>, or an arrayref where the first
777             item is one of the previous two things and the remainder are treated as
778             arguments to curry to the first argument. A quoted regexp C<< qr/.../ >> can
779             also be used as a callable.
780              
781             If using an arrayref, it is generally permissable to flatten it into a
782             list, unless otherwise noted. An example of this can be seen in the
783             documentation for C<select>.
784              
785             =over
786              
787             =item C<< select( CALLABLE ) >>
788              
789             LINQ's version of C<map>, except that the code given is always called in
790             scalar context, being expected to return exactly one result.
791              
792             Returns a LINQ::Collection of the results.
793              
794             my $people = LINQ( [
795             { name => "Alice", age => 32 },
796             { name => "Bob", age => 31 },
797             { name => "Carol", age => 34 },
798             ] );
799            
800             my $names = $people->select( sub {
801             return $_->{name};
802             } );
803            
804             for my $name ( $names->to_list ) {
805             print "$name\n";
806             }
807              
808             Another way of doing the same thing, using currying:
809              
810             my $people = LINQ( [
811             { name => "Alice", age => 32 },
812             { name => "Bob", age => 31 },
813             { name => "Carol", age => 34 },
814             ] );
815            
816             my $BY_HASH_KEY = sub {
817             my ($key) = @_;
818             return $_->{$key};
819             };
820            
821             my $names = $people->select( $BY_HASH_KEY, 'name' );
822            
823             for my $name ( $names->to_list ) {
824             print "$name\n";
825             }
826              
827             =item C<< select_many( CALLABLE ) >>
828              
829             If you wanted C<select> to be able to return a list like C<map> does, then
830             C<select_many> is what you want. However, rather than returning a Perl list,
831             your callable should return a LINQ::Collection or an arrayref.
832              
833             =item C<< where( CALLABLE ) >>
834              
835             LINQ's version of C<grep>. Returns a LINQ::Collection of the filtered results.
836              
837             my $people = LINQ( [
838             { name => "Alice", age => 32 },
839             { name => "Bob", age => 31 },
840             { name => "Carol", age => 34 },
841             ] );
842            
843             my $young_people = $people->where( sub {
844             return $_->{age} < 33;
845             } );
846              
847             =item C<< min( CALLABLE? ) >>
848              
849             Returns the numerically lowest value in the collection.
850              
851             my $lowest = LINQ( [ 5, 1, 2, 3 ] )->min; # ==> 1
852              
853             If a callable is provided, then C<select> will be called and the minimum of the
854             result will be returned.
855              
856             my $people = LINQ( [
857             { name => "Alice", age => 32 },
858             { name => "Bob", age => 31 },
859             { name => "Carol", age => 34 },
860             ] );
861            
862             my $lowest_age = $people->min( sub { $_->{age} } ); # ==> 31
863              
864             If you need more flexible comparison (e.g. non-numeric comparison), use
865             C<order_by> followed by C<first>.
866              
867             =item C<< max( CALLABLE? ) >>
868              
869             Like C<min>, but returns the numerically highest value.
870              
871             =item C<< sum( CALLABLE? ) >>
872              
873             Like C<min>, but returns the sum of all values in the collection.
874              
875             =item C<< average( CALLABLE? ) >>
876              
877             Takes C<sum>, and divides by the count of items in the collection.
878              
879             my $people = LINQ( [
880             { name => "Alice", age => 32 },
881             { name => "Bob", age => 31 },
882             { name => "Carol", age => 34 },
883             ] );
884            
885             my $average_age = $people->average( sub {
886             return $_->{age};
887             } ); # ==> 32.33333
888              
889             =item C<< aggregate( CALLABLE, INITIAL? ) >>
890              
891             LINQ's version of C<reduce> (from L<List::Util>). We pass C<< $a >> and
892             C<< $b >> as the last arguments to CALLABLE, rather than using the package
893             variables like List::Util does.
894              
895             The CALLABLE must not be a flattened list, but may still be an arrayref.
896             INITIAL is an initial value.
897              
898             my $people = LINQ( [
899             { name => "Alice", age => 32 },
900             { name => "Bob", age => 31 },
901             { name => "Carol", age => 34 },
902             ] );
903            
904             my dotted_names = $people
905             ->select( sub { $_->{name} } )
906             ->aggregate( sub {
907             my ( $a, $b ) = @_;
908             return "$a.$b";
909             } );
910            
911             print "$dotted_names\n"; # ==> Alice.Bob.Carol
912              
913             =item C<< join( Y, HINT?, X_KEYS, Y_KEYS, JOINER ) >>
914              
915             This is akin to an SQL join.
916              
917             my $people = LINQ( [
918             { name => "Alice", dept => 'Marketing' },
919             { name => "Bob", dept => 'IT' },
920             { name => "Carol", dept => 'IT' },
921             ] );
922            
923             my $departments = LINQ( [
924             { dept_name => 'Accounts', cost_code => 1 },
925             { dept_name => 'IT', cost_code => 7 },
926             { dept_name => 'Marketing', cost_code => 8 },
927             ] );
928            
929             my $BY_HASH_KEY = sub {
930             my ($key) = @_;
931             return $_->{$key};
932             };
933            
934             my $joined = $people->join(
935             $departments,
936             -inner, # inner join
937             [ $BY_HASH_KEY, 'dept' ], # select from $people
938             [ $BY_HASH_KEY, 'dept_name' ], # select from $departments
939             sub {
940             my ( $person, $dept ) = @_;
941             return {
942             name => $person->{name},
943             dept => $person->{dept},
944             expense_code => $dept->{cost_code},
945             };
946             },
947             );
948              
949             Hints C<< -inner >>, C<< -left >>, C<< -right >>, and C<< -outer >> are
950             supported, analagous to the joins with the same names in SQL.
951              
952             X_KEYS and Y_KEYS are non-list callables which return the values to join the
953             two collections by.
954              
955             JOINER is a callable (which may be a flattened list) which is passed items
956             from each of the two collections and should return a new item. In the case
957             of left/right/outer joins, one of those items may be undef.
958              
959             =item C<< group_join( Y, HINT?, X_KEYS, Y_KEYS, JOINER ) >>
960              
961             Similar to C<group> except that rather than JOINER being called for every
962             X/Y combination, all the Ys for a particular X are put in a collection, and
963             the JOINER is called for each X and passed the collection of Ys.
964              
965             The only hints supported are C<< -inner >> and C<< -left >>.
966              
967             This is best explained with a full example:
968              
969             my $departments = LINQ( [
970             { dept_name => 'Accounts', cost_code => 1 },
971             { dept_name => 'IT', cost_code => 7 },
972             { dept_name => 'Marketing', cost_code => 8 },
973             ] );
974            
975             my $people = LINQ( [
976             { name => "Alice", dept => 'Marketing' },
977             { name => "Bob", dept => 'IT' },
978             { name => "Carol", dept => 'IT' },
979             ] );
980            
981             my $BY_HASH_KEY = sub {
982             my ($key) = @_;
983             return $_->{$key};
984             };
985            
986             my $joined = $departments->group_join(
987             $people,
988             -left, # left join
989             [ $BY_HASH_KEY, 'dept_name' ], # select from $departments
990             [ $BY_HASH_KEY, 'dept' ], # select from $people
991             sub {
992             my ( $dept, $people ) = @_; # $people is a LINQ::Collection
993             my $names = $people->select( $BY_HASH_KEY, 'name' )->to_array;
994             return {
995             dept => $dept->{dept_name},
996             cost_code => $dept->{cost_code},
997             people => $names,
998             };
999             },
1000             );
1001            
1002             # [
1003             # {
1004             # 'cost_code' => 1,
1005             # 'dept' => 'Accounts',
1006             # 'people' => []
1007             # },
1008             # {
1009             # 'cost_code' => 7,
1010             # 'dept' => 'IT',
1011             # 'people' => [
1012             # 'Bob',
1013             # 'Carol'
1014             # ]
1015             # },
1016             # {
1017             # 'cost_code' => 8,
1018             # 'dept' => 'Marketing',
1019             # 'people' => [
1020             # 'Alice'
1021             # ]
1022             # }
1023              
1024             =item C<< take( N ) >>
1025              
1026             Takes just the first N items from a collection, returning a new collection.
1027              
1028             =item C<< take_while( CALLABLE ) >>
1029              
1030             Takes items from the collection, stopping at the first item where CALLABLE
1031             returns false.
1032              
1033             If CALLABLE dies, there are some issues on older versions of Perl with the
1034             error message getting lost.
1035              
1036             =item C<< skip( N ) >>
1037              
1038             Skips the first N items from a collection, and returns the rest as a new
1039             collection.
1040              
1041             =item C<< skip_while( CALLABLE ) >>
1042              
1043             Skips the first items from a collection while CALLABLE returns true, and
1044             returns the rest as a new collection.
1045              
1046             =item C<< concat( COLLECTION ) >>
1047              
1048             Returns a new collection by concatenating this collection with another
1049             collection.
1050              
1051             my $deck_of_cards = $red_cards->concat( $black_cards );
1052              
1053             =item C<< order_by( HINT?, CALLABLE? ) >>
1054              
1055             HINT may be C<< -numeric >> (the default) or C<< -string >>.
1056              
1057             If CALLABLE is given, it should return a number or string to sort by.
1058              
1059             my $sorted = $people->order_by(
1060             -string,
1061             [ $BY_HASH_KEY, 'name' ] # CALLABLE as an arrayref
1062             );
1063              
1064             =item C<< then_by( HINT?, CALLABLE ) >>
1065              
1066             Not implemented.
1067              
1068             =item C<< order_by_descending( HINT?, CALLABLE ) >>
1069              
1070             Like C<order_by> but uses reverse order.
1071              
1072             =item C<< then_by_descending( HINT?, CALLABLE ) >>
1073              
1074             Not implemented.
1075              
1076             =item C<< reverse >>
1077              
1078             Reverses the order of the collection.
1079              
1080             =item C<< group_by( CALLABLE ) >>
1081              
1082             Groups the items by the key returned by CALLABLE.
1083              
1084             The collection of groups is a LINQ::Collection and each grouping is a
1085             LINQ::Grouping. LINQ::Grouping provides two accessors: C<key> and C<values>,
1086             with C<values> returning a LINQ::Collection of items.
1087              
1088             my $people = LINQ( [
1089             { name => "Alice", dept => 'Marketing' },
1090             { name => "Bob", dept => 'IT' },
1091             { name => "Carol", dept => 'IT' },
1092             ] );
1093            
1094             my $groups = $people->group_by( sub { $_->{dept} } );
1095            
1096             for my $group ( $groups->to_list ) {
1097             print "Dept: ", $group->key, "\n";
1098            
1099             for my $person ( $group->values->to_list ) {
1100             print " - ", $person->{name};
1101             }
1102             }
1103              
1104             =item C<< distinct( CALLABLE? ) >>
1105              
1106             Returns a new collection without any duplicates which were in the original.
1107              
1108             If CALLABLE is provided, this will be used to determine when two items are
1109             considered identical/equivalent. Otherwise, numeric equality is used.
1110              
1111             =item C<< union( COLLECTION, CALLABLE? ) >>
1112              
1113             Returns a new collection formed from the union of both collections.
1114              
1115             my $first = LINQ( [ 1, 2, 3, 4 ] );
1116             my $second = LINQ( [ 3, 4, 5, 6 ] );
1117            
1118             $first->union( $second )->to_array; # ==> [ 1, 2, 3, 4, 5, 6 ]
1119              
1120             If CALLABLE is provided, this will be used to determine when two items are
1121             considered identical/equivalent. Otherwise, numeric equality is used.
1122              
1123             =item C<< intersect( COLLECTION, CALLABLE? ) >>
1124              
1125             Returns a new collection formed from the union of both collections.
1126              
1127             my $first = LINQ( [ 1, 2, 3, 4 ] );
1128             my $second = LINQ( [ 3, 4, 5, 6 ] );
1129            
1130             $first->intersect( $second )->to_array; # ==> [ 3, 4 ]
1131              
1132             If CALLABLE is provided, this will be used to determine when two items are
1133             considered identical/equivalent. Otherwise, numeric equality is used.
1134              
1135             =item C<< except( COLLECTION, CALLABLE? ) >>
1136              
1137             Returns a new collection formed from the asymmetric difference of both
1138             collections.
1139              
1140             my $first = LINQ( [ 1, 2, 3, 4 ] );
1141             my $second = LINQ( [ 3, 4, 5, 6 ] );
1142            
1143             $first->except( $second )->to_array; # ==> [ 1, 2 ]
1144              
1145             If CALLABLE is provided, this will be used to determine when two items are
1146             considered identical/equivalent. Otherwise, numeric equality is used.
1147              
1148             =item C<< sequence_equal( COLLECTION, CALLABLE? ) >>
1149              
1150             Returns true if and only if each item in the first collection is
1151             identical/equivalent to its corresponding item in the second collection,
1152             considered in order, according to CALLABLE.
1153              
1154             If CALLABLE isn't given, then numeric equality is used.
1155              
1156             =item C<< first( CALLABLE? ) >>
1157              
1158             Returns the first item in a collection.
1159              
1160             If CALLABLE is provided, returns the first item in the collection where
1161             CALLABLE returns true.
1162              
1163             If there is no item to return, does not return undef, but throws a
1164             LINQ::Exception::NotFound exception.
1165              
1166             =item C<< first_or_default( CALLABLE?, DEFAULT ) >>
1167              
1168             Like C<first>, but instead of throwing an exception, will return the DEFAULT.
1169              
1170             =item C<< last( CALLABLE? ) >>
1171              
1172             Returns the last item in a collection.
1173              
1174             If CALLABLE is provided, returns the last item in the collection where
1175             CALLABLE returns true.
1176              
1177             If there is no item to return, does not return undef, but throws a
1178             LINQ::Exception::NotFound exception.
1179              
1180             =item C<< last_or_default( CALLABLE?, DEFAULT ) >>
1181              
1182             Like C<last>, but instead of throwing an exception, will return the DEFAULT.
1183              
1184             =item C<< single( CALLABLE? ) >>
1185              
1186             Returns the only item in a collection.
1187              
1188             If CALLABLE is provided, returns the only item in the collection where
1189             CALLABLE returns true.
1190              
1191             If there is no item to return, does not return undef, but throws a
1192             LINQ::Exception::NotFound exception.
1193              
1194             If there are multiple items in the collection, or multiple items where
1195             CALLABLE returns true, throws a LINQ::Exception::MultipleFound exception.
1196              
1197             =item C<< single_or_default( CALLABLE?, DEFAULT ) >>
1198              
1199             Like C<single> but rather than throwing an exception, will return DEFAULT.
1200              
1201             =item C<< element_at( N ) >>
1202              
1203             Returns element N within the collection. N may be negative to count from the
1204             end of the collection. Collections are indexed from zero.
1205              
1206             If N exceeds the length of the collection, throws a LINQ::Exception::NotFound
1207             exception.
1208              
1209             =item C<< element_at_or_default( N, DEFAULT ) >>
1210              
1211             Like C<element_at> but rather than throwing an exception, will return DEFAULT.
1212              
1213             =item C<< any( CALLABLE? ) >>
1214              
1215             Returns true if CALLABLE returns true for any item in the collection.
1216              
1217             =item C<< all( CALLABLE? ) >>
1218              
1219             Returns true if CALLABLE returns true for every item in the collection.
1220              
1221             =item C<< contains( ITEM, CALLABLE? ) >>
1222              
1223             Returns true if the collection contains ITEM. By default, this is checked
1224             using numeric equality.
1225              
1226             If CALLABLE is given, this is passed two items and should return true
1227             if they should be considered identical/equivalent.
1228              
1229             my $SAME_NAME = sub {
1230             $_[0]{name} eq $_[1]{name};
1231             };
1232            
1233             if ( $people->contains( { name => "Bob" }, $SAME_NAME ) ) {
1234             print "The collection includes Bob.\n";
1235             }
1236              
1237             =item C<< count >>
1238              
1239             Returns the size of the collection. (Number of items.)
1240              
1241             =item C<< to_list >>
1242              
1243             Returns the collection as a list.
1244              
1245             =item C<< to_array >>
1246              
1247             Returns an arrayref for the collection. This may be a tied arrayref and you
1248             should not assume it will be writable.
1249              
1250             =item C<< to_dictionary( CALLABLE ) >>
1251              
1252             The CALLABLE will be called for each item in the collection and is expected to
1253             return a string key.
1254              
1255             The method will return a hashref mapping the keys to each item in the
1256             collection.
1257              
1258             =item C<< to_lookup( CALLABLE ) >>
1259              
1260             Alias for C<to_dictionary>.
1261              
1262             =item C<< to_iterator >>
1263              
1264             Returns a coderef which can be used to iterate through the collection.
1265              
1266             my $people = LINQ( [
1267             { name => "Alice", dept => 'Marketing' },
1268             { name => "Bob", dept => 'IT' },
1269             { name => "Carol", dept => 'IT' },
1270             ] );
1271            
1272             my $next_person = $people->to_iterator;
1273            
1274             while ( my $person = $next_person->() ) {
1275             print $person->{name}, "\n";
1276             }
1277              
1278             =item C<< cast( TYPE ) >>
1279              
1280             Given a type constraint (see L<Type::Tiny>) will attempt to coerce every item
1281             in the collection to the type, and will return the collection of coerced
1282             values. If any item cannot be coerced, throws a LINQ::Exception::Cast
1283             exception.
1284              
1285             =item C<< of_type( TYPE ) >>
1286              
1287             Given a type constraint (see L<Type::Tiny>) will attempt to coerce every item
1288             in the collection to the type, and will return the collection of coerced
1289             values. Any items which cannot be coerced will be skipped.
1290              
1291             =item C<< zip( COLLECTION, CALLABLE ) >>
1292              
1293             Will loop through both collections in parallel and pass one item from each
1294             collection to CALLABLE as arguments.
1295              
1296             If the two collections are of different sizes, will stop after exhausing the
1297             shorter collection.
1298              
1299             =item C<< default_if_empty( ITEM ) >>
1300              
1301             If this collection contains one or more items, returns itself.
1302              
1303             If the collection is empty, returns a new collection containing just a single
1304             item, given as a parameter.
1305              
1306             my $collection = $people->default_if_empty( "Bob" );
1307            
1308             # Equivalent to:
1309             my $collection = $people->count ? $people : LINQ( [ "Bob" ] );
1310              
1311             =item C<< foreach( CALLABLE ) >>
1312              
1313             This calls CALLABLE on each item in the collection. The following are roughly
1314             equivalent:
1315              
1316             for ( $collection->to_list ) {
1317             say $_;
1318             }
1319            
1320             $collection->foreach( sub {
1321             say $_;
1322             } );
1323              
1324             The advantage of the latter is that it avoids calling C<to_list>, which would
1325             obviously fail on infinite collections.
1326              
1327             You can break out of the loop using C<< LINQ::LAST >>.
1328              
1329             my $counter = 0;
1330             $collection->foreach( sub {
1331             say $_;
1332             LINQ::LAST if ++$counter >= 10;
1333             } );
1334              
1335             Microsoft's official LINQ API doesn't include a C<ForEach> method, but this
1336             method is provided by the MoreLINQ extension.
1337              
1338             =back
1339              
1340             =head1 WORKING WITH INFINITE COLLECTIONS
1341              
1342             Because LINQ collections can be instantiated from an iterator, they may
1343             contain infinite items.
1344              
1345             Certain methods aggregate the entire collection, so can go into an infinite
1346             loop. This includes: C<aggregate>, C<min>, C<max>, C<sum>, C<average>, and
1347             C<count>.
1348              
1349             Other methods which will go into an infinite loop on infinite collections:
1350             C<join>, C<group_join>, C<group_by>, C<order_by>, C<order_by_descending>,
1351             C<reverse>, C<to_lookup>, C<to_dictionary>, and C<to_list>.
1352              
1353             The C<to_array> method in general I<will> succeed on infinite collections
1354             as it can return a reference to a tied array. However, trying to dereference
1355             the entire array to a list will fail.
1356              
1357             =head1 BUGS
1358              
1359             Please report any bugs to
1360             L<http://rt.cpan.org/Dist/Display.html?Queue=LINQ>.
1361              
1362             =head1 SEE ALSO
1363              
1364             L<LINQ>, L<LINQ::Grouping>.
1365              
1366             L<https://en.wikipedia.org/wiki/Language_Integrated_Query>
1367              
1368             =head1 AUTHOR
1369              
1370             Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
1371              
1372             =head1 COPYRIGHT AND LICENCE
1373              
1374             This software is copyright (c) 2014, 2021 by Toby Inkster.
1375              
1376             This is free software; you can redistribute it and/or modify it under
1377             the same terms as the Perl 5 programming language system itself.
1378              
1379             =head1 DISCLAIMER OF WARRANTIES
1380              
1381             THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
1382             WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1383             MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.