Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

How to return a list using recursion?

by dr.jekyllandme (Sexton)
on Aug 07, 2012 at 00:53 UTC ( #985857=perlquestion: print w/ replies, xml ) Need Help??
dr.jekyllandme has asked for the wisdom of the Perl Monks concerning the following question:

Hello, I need help writing a recursive subroutine that will return an array. I would like to do something similar to PHP's array_chunk. Let's say I have a list of elements:
@list = ( 'a' .. 'z' );
I want to set a limit of 5 characters for each array element separated by spaces and ending in a comma if the array will have more elements following it. The expected output:
a b c d e, # arr[0] f g h i j, # arr[1] k l m n o, # arr[2] p q r s t, # arr[3] u v w x y, # arr[4] z # arr[5]
So far, I have achieved this output by returning a string separated by newlines. I could get a list at this point by splitting on newline, but I would like to get a list instead. The only problem is that I am not sure how to return a list using recursion. My code so far:
#!usr/bin/perl use strict; use warnings; my @list = ( 'a' .. 'z' ); my $string_chunk5 = _string_chunk5( @list ); my @array_chunk5 = _array_chunk5( @list ); print "String chunk of 5 =\n$string_chunk5\n"; print "Array chunk of 5 =\n@array_chunk5\n"; sub _string_chunk5 { my @arr = @_; return join( " ", @arr ) unless @arr > 5; return join( " ", splice( @arr, 0, 5 ) ). ",\n" . _string_chunk5( +@arr ); } sub _array_chunk5 { my @arr = @_; # Base case == when @arr is <= 5 return ( join( " ", @arr ) ) unless @arr > 5; # what goes here ? }
Any pointers would be a great help. Thank you for your time.

Comment on How to return a list using recursion?
Select or Download Code
Re: How to return a list using recursion?
by Athanasius (Monsignor) on Aug 07, 2012 at 02:38 UTC

    Use array references:

    #! perl use strict; use warnings; my @list = ( 'a' .. 'z' ); my @array_chunk5 = _array_chunk5( @list ); print "Array chunk of 5 =\n"; my $count; print "Chunk ", ++$count, ":\n", join("\n", @$_), "\n\n" for @array_ch +unk5; sub _array_chunk5 { my @arr = @_; if (@arr > 5) { my @chunk; push(@chunk, shift @arr) for (1 .. 5); return ( \@chunk, _array_chunk5(@arr) ); } else { return \@arr; } }

    HTH,

    Athanasius <°(((><contra mundum

Re: How to return a list using recursion?
by Anonymous Monk on Aug 07, 2012 at 03:39 UTC

    Well, this isn't something you should use recursion for

    #!/usr/bin/perl -- use strict; use warnings; use Data::Dump; use List::AllUtils qw' natatime '; my @x = ('a' .. 'z'); my $it = natatime 5, @x; my @yo; while (my @vals = $it->()) { push @yo, "@vals,\n"; } chomp $yo[-1]; chop $yo[-1]; dd \@yo; __END__ [ "a b c d e,\n", "f g h i j,\n", "k l m n o,\n", "p q r s t,\n", "u v w x y,\n", "z", ]
      this isn't something you should use recursion for

      s/should/need to/

      You also don’t need a module. Here is a solution using a stateful subroutine as an iterator:

      #! perl use strict; use warnings; my @list = ('a' .. 'z'); my $size = 5; _array_chunk_it($size, @list); while (my @chunk = _array_chunk_it()) { print "Array chunk of $size =\n", join("\n", @chunk), "\n\n"; } { my ($array, $count); sub _array_chunk_it { my @chunk; if (@_) { $count = shift; $array = [ @_ ]; } else { for (1 .. $count) { push(@chunk, shift @$array) if @$array; } } return @chunk; } }

      (With newer versions of Perl, this can be rewritten using state.)

      TMTOWTDI :-)

      Update: ++Anonymous Monk for the superior version using a closure, below.

      Athanasius <°(((><contra mundum

        With older versions of Perl, it can be rewritten as a proper iterator :-)

        use strict; use warnings; my @list = ('a' .. 'z'); my $size = 5; my $chunker = _array_chunk_it($size, @list); while (my @chunk = $chunker->()) { print "Array chunk of $size =\n", join("\n", @chunk), "\n\n"; } sub _array_chunk_it { my ($count, @array) = @_; return sub { my @chunk; for (1 .. $count) { push(@chunk, shift @array) if @array; } return @chunk; } }

        (Using a closure we can actually call _array_chunk_it multiple times, in an overlapping manner. Have multiple iterators running simultaneously. Plus it looks quite a bit nicer.)

        this isn't something you should use recursion for

        s/should/need to/

        :) I meant should not, esp since there is nothing particularly recursive about it (you have to squint to make it recursive)

        You also donít need a module.

        Sure I do :) otherwise I'm writing the the idiomatic perl solution

        It was real hard to come up with

        #!/usr/bin/perl -- use strict; use warnings; my @x = ('a' .. 'z'); print yup( 5, @x ),"\n--\n"; print yup( 3, @x ),"\n"; sub yup { my( $n, @x ) = @_; my @yo; for( my $ix = 0; $ix < @x; $ix += $n ) { my $high = $n - 1 + $ix ; $high > $#x and $high = $#x ; push @yo, join ' ', @x[ $ix .. $high ]; } return join ",\n", @yo; } __END__ a b c d e, f g h i j, k l m n o, p q r s t, u v w x y, z -- a b c, d e f, g h i, j k l, m n o, p q r, s t u, v w x, y z
Re: How to return a list using recursion?
by BrowserUk (Pope) on Aug 07, 2012 at 04:53 UTC

    sub chunks{ my( $n, @in ) = @_; join ",\n", map join(' ', splice @in, 0, $n), 0 .. $#in / $n; };; print chunks( 3, 'a'..'z' );; a b c, d e f, g h i, j k l, m n o, p q r, s t u, v w x, y z print chunks( 10, 'a'..'z' );; a b c d e f g h i j, k l m n o p q r s t, u v w x y z print chunks( 26, 'a'..'z' );; a b c d e f g h i j k l m n o p q r s t u v w x y z print chunks( 13, 'a'..'z' );; a b c d e f g h i j k l m, n o p q r s t u v w x y z print chunks( 6, 'a'..'z' );; a b c d e f, g h i j k l, m n o p q r, s t u v w x, y z

    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

    The start of some sanity?

Re: How to return a list using recursion?
by tobyink (Abbot) on Aug 07, 2012 at 05:45 UTC

    I agree that this isn't necessarily the best task to use recursion for, but here's one possibility:

    use Data::Dumper; sub mk_chunker { my $n = shift; die unless $n > 0; my $sub; return $sub = sub { return \@_ if @_ < $n; return ( [ @_[0..$n-1] ], $sub->(@_[$n..$#_]), # recursion ); }; } *chunk_5 = mk_chunker(5); print Dumper chunk_5('a' .. 'z');

    The closure in mk_chunker is a good candidate for Perl 5.16's new __SUB__ feature...

    use 5.016; sub mk_chunker { my $n = shift; die unless $n > 0; return sub { return \@_ if @_ < $n; return ( [ @_[0..$n-1] ], __SUB__->(@_[$n..$#_]), # recursion ); }; }
    perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
Re: How to return a list using recursion?
by ig (Vicar) on Aug 07, 2012 at 06:11 UTC
    what goes here?
    sub _array_chunk5 { my @arr = @_; # Base case == when @arr is <= 5 return ( join( " ", @arr ) ) unless @arr > 5; # what goes here ? return ( join( " ", splice ( @arr, 0, 5 ) ) , _array_chunk5(@arr) + ); }

    But I might write it more like:

    sub _array_chunk5x { my @arr = @_; return ( ) if(@arr == 0); return ( join( " ", splice( @arr, 0, 5 ) ), _array_chunk5(@arr) ); }
Re: How to return a list using recursion?
by johngg (Abbot) on Aug 07, 2012 at 11:06 UTC

    Another recursive solution using a subroutine that takes a block of code to execute against a "chunked" list.

    use strict; use warnings; use 5.010; sub groupsOf (&$@); my @list = ( q{a} .. q{z} ); say for groupsOf { qq{@_,} } 5, @list; say for groupsOf { qq{@_,} } 7, @list; sub groupsOf (&$@) { my $rcToRun = shift; my $groupsOf = shift; my $rcDoIt; $rcDoIt = sub { $rcToRun->( map shift, 1 .. ( @_ < $groupsOf ? @_ : $groupsOf ) ), @_ ? &$rcDoIt : (); }; &$rcDoIt; }

    I hope this is of interest.

    Update: Oops, forgot to post the output :-(

    a b c d e, f g h i j, k l m n o, p q r s t, u v w x y, z, a b c d e f g, h i j k l m n, o p q r s t u, v w x y z,

    Cheers,

    JohnGG

Re: How to return a list using recursion?
by BillKSmith (Chaplain) on Aug 07, 2012 at 16:34 UTC
    "# what goes here ?"
    return ( join( ' ', splice(@arr, 0, 5)) . ",\n" , _array_chunk5(@arr), );

    Update: Sorry, I did not notice that this is the same as IG's solution.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://985857]
Approved by BrowserUk
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others about the Monastery: (14)
As of 2014-07-31 20:14 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My favorite superfluous repetitious redundant duplicative phrase is:









    Results (252 votes), past polls