http://qs321.pair.com?node_id=861938

Following the educational tradition of:

this meditation describes an arbitrary problem to be solved in different ways and in different languages.

The Problem

Given a list of strings, for example ("a", "bb", "c", "d", "e", "f", "g", "h"), and a chunksize, for example 3, write a subroutine to return a multi-line string, for example:

a bb c d e f g h
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.

Perl

Here was my first Perl attempt:

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;

I trust this initial solution will clarify the problem specification.

Being dissatisfied with this ugly first attempt, I next took at a look at the core List::Util and the non-core List::MoreUtils modules, writing two different solutions using List::MoreUtils, one using natatime, the other part, as shown below:

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 +; }

Python

For cheap thrills, I hacked out a Python itertools-based solution.

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))

Discussion

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.

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.

Update: See also Re: How to Split on specific occurrence of a comma (2020)