perlmeditation eyepopslikeamosquito <P> Following the educational tradition of: <ul> <li><a href="https://www.rosettacode.org/">Rosetta code</a> <li><a href="https://www.ic.unicamp.br/~meidanis/courses/mc336/2006s2/funcional/L-99_Ninety-Nine_Lisp_Problems.html">99 Lisp Problems</a> <li>[id://589260] <li>[id://632023] </ul> this meditation describes an arbitrary problem to be solved in different ways and in different languages. </P> <P><B>The Problem</B></P> <P> Given a list of strings, for example <CODE>("a", "bb", "c", "d", "e", "f", "g", "h")</CODE>, and a chunksize, for example <C>3</C>, write a subroutine to return a multi-line string, for example: <CODE> a bb c d e f g h </CODE> The output string must contain a single space between each array element and a newline every chunksize items. Note that no trailing space is permitted on any line and the last line must be properly newline-terminated. </P> <P><B>Perl</B></P> <P> Here was my first Perl attempt: <CODE> use strict; use warnings; sub chunk_array { my (\$n, @vals) = @_; my \$str; my \$i = 0; for my \$v (@vals) { ++\$i; \$str .= \$v . ( (\$i % \$n) ? " " : "\n" ); } substr(\$str, -1, 1) = "\n"; return \$str; } my \$v1 = chunk_array(3, "a", "bb", "c", "d", "e", "f", "g", "h"); \$v1 eq "a bb c\nd e f\ng h\n" or die "error: '\$v1'\n"; print \$v1; my \$v2 = chunk_array(3, "a", "bb", "c", "d", "e", "f"); \$v2 eq "a bb c\nd e f\n" or die "error: '\$v2'\n"; print \$v2; </CODE> </P> <P> I trust this initial solution will clarify the problem specification. </P> <P> Being dissatisfied with this ugly first attempt, I next took at a look at the core List::Util and the non-core <a href="http://search.cpan.org/dist/List-MoreUtils/">List::MoreUtils</a> modules, writing two different solutions using List::MoreUtils, one using <C>natatime</C>, the other <C>part</C>, as shown below: <CODE> use List::MoreUtils qw(part natatime); sub chunk_array { my (\$n, @vals) = @_; my \$str; my \$iter = natatime(\$n, @vals); while ( my @line = \$iter->() ) { \$str .= join(" ", @line) . "\n"; } return \$str; } sub chunk_array { my (\$n, @vals) = @_; my \$i = 0; return join "", map { join(" ", @\$_)."\n" } part { \$i++/\$n } @vals; } </CODE> </P> <P><B>Python</B></P> <P> For cheap thrills, I hacked out a Python itertools-based solution. <CODE> from itertools import * def group(n, iterable): args = [iter(iterable)] * n return izip_longest(*args) def chunk_array(n, vals): return "".join(" ".join(x for x in i if x!=None)+"\n" for i in group(n, vals)) </CODE> </P> <P><B>Discussion</B></P> <P> I've derived little enjoyment so far from any of my solutions and accordingly encourage you to show us a more elegant way to solve this simple problem. </P> <P> Please feel free to contribute more Perl solutions or a solution in any language you fancy. I'm especially eager to admire a Perl 6 solution. </P> <P> <B>Update:</B> See also [id://11124614] (2020) </P>