PWC186 - Zip List


Here we are with TASK #1 from The Weekly Challenge #186. Enjoy!

The challenge

You are given two list @a and @b of same size.

Create a subroutine sub zip(@a, @b) that merge the two list as shown in the example below.


Input:  @a = qw/1 2 3/; @b = qw/a b c/;
Output: zip(@a, @b) should return qw/1 a 2 b 3 c/;
        zip(@b, @a) should return qw/a 1 b 2 c 3/;

The questions

Uhm… I guess I can nitpick a bit and observe that @a and @b are two arrays. For everything else, I’ll trust that the user of the function feeds in the input stuff exactly as stated.

The solution

The nitpicking in the questions section is not merely to nag our fine host.

If we indeed have two arrays, then we can implement functions that expect arrays. So in Raku we would have:

#!/usr/bin/env raku
use v6;
sub MAIN {
   my @a = <1 2 3>;
   my @b = <a b c>;
   zip(@a, @b).say;
   zip(@b, @a).say;

sub zip (@a, @b) { (@a Z @b).flat }

Don’t ask… but yes, I missed the .flat in the first try.

In Perl we can do some prototypes magic (perldoc perlsub if you’re curious) and obtain a similar result:

#!/usr/bin/env perl
use v5.24;
use warnings;

sub zip(\@\@);

my @a = qw< 1 2 3 >;
my @b = qw< a b c >;
say "(@{[ zip(@a, @b) ]})";
say "(@{[ zip(@b, @a) ]})";

sub zip (\@\@) {
   my ($A, $B) = @_;
   map { ($A->[$_], $B->[$_]) } 0 .. $A->$#*;

On the other hand, if we’re dealing with the looser concept of lists, and for example we first merge the two arrays into a single one and then feed it as a list of items, bad things will happen. In Perl terms:

say "(@{[ zip(@{[ @a, @b ]}) ]})";

# Not enough arguments for main::zip...

So, of course, we can look at the problem from a pure list angle, and assume that we will be given a single list composed of an even number of elements, which we can split into two parts that we can then zip:

sub listy_zip {
   my @A = splice @_, 0, @_ / 2;
   my @B = @_
   map { ($A[$_], $B[$_]) } 0 .. $#A;

We might even cheat a bit with this implementation and (ab)use signatures:

sub listy_zip (@B, @A) {
   @A = splice @B, 0, @B / 2;
   map { ($A[$_], $B[$_]) } 0 .. $#A;

This would be blatant lying, right?

Stay safe!

Comments? Octodon, , GitHub, Reddit, or drop me a line!