Perl Weekly Challenge 256: Merge Strings

These are some answers to the Week 256, Task 2, of the Perl Weekly Challenge organized by Mohammad S. Anwar.

Spoiler Alert: This weekly challenge deadline is due in a few days from now (on February 18, 2024 at 23:59). This blog post provides some solutions to this challenge. Please don’t read on if you intend to complete the challenge on your own.

Task 2: Merge Strings

You are given two strings, $str1 and $str2.

Write a script to merge the given strings by adding in alternative order starting with the first string. If a string is longer than the other then append the remaining at the end.

Example 1

Input: $str1 = "abcd", $str2 = "1234"
Output: "a1b2c3d4"

Example 2

Input: $str1 = "abc", $str2 = "12345"
Output: "a1b2c345"

Example 3

Input: $str1 = "abcde", $str2 = "123"
Output: "a1b2c3de"

Merge Strings in Raku

For such a task, the first thing that comes to mind in Raku is to use the built-in zip routine, which iterates through each of the input lists synchronously, 'Zipping' them together, so that elements are grouped according to their input list index, in the order that the lists are provided. The slight problem, though, is that, if the input lists have an unequal number of elements, then zip terminates once the shortest input list is exhausted, and trailing elements from longer input lists are discarded. This is not what we want here, since the task says: "If a string is longer than the other, then append the remaining at the end." We could still use zip and add at the end the left-overs from the longer list, but we can do better.

Raku has another built-in similar routine, roundrobin, which does not terminate once one or more of the input lists become exhausted, but proceeds until all elements from all lists have been processed. This is exactly what we need here, and the work is done with just one code-line.

sub merge-strings ($str1, $str2) {
    my $res = join "", roundrobin $str1.comb, $str2.comb, :slip;
    return $res;
}

my @tests = <abcd 1234>, <abc 12345>, <abcde 123>;
for @tests -> @test {
    printf "%-12s => ", "@test[]";
    say merge-strings @test[0], @test[1];
}

This program displays the following output:

$ raku ./merge-strings.raku
abcd 1234    => a1b2c3d4
abc 12345    => a1b2c345
abcde 123    => a1b2c3de

Merge Strings in Perl

Perl doesn't have built-in routines such as zip or roundrobin, so we need to build the result manually. We loop over the indexes of the longer list and add the items from both lists (or an empty string if a value is not defined for a given index).

use strict;
use warnings;
use feature 'say';

sub merge_strings  {
    my ($str1, $str2) = @_;
    my @let1 = split //, $str1;
    my @let2 = split //, $str2;
    my $end = scalar @let1 > scalar @let2 ? $#let1 : $#let2;
    my @result = map { ($let1[$_] // "") . 
                       ($let2[$_] // "") } 0..$end;
    return join "", @result;
}

my @tests = ([<abcd 1234>], [<abc 12345>], [<abcde 123>]);
for my $test (@tests) {
    printf "%-12s => ", "@$test";
    say merge_strings $test->[0], $test->[1];
}

This program displays the following output:

$ perl ./merge-strings.pl
abcd 1234    => a1b2c3d4
abc 12345    => a1b2c345
abcde 123    => a1b2c3de

Merge Strings in Julia

Yet a slightly different method. We loop over the indexes of the shorter list and add the items from both lists. At the end, we add at the end the trailing items from the longer list.

using Printf

function merge_strings(str1, str2) 
    result = []
    let1 = split(str1, "")
    let2 = split(str2, "")
    size1 = size(let1, 1)
    size2 = size(let2, 1)
    last_i = size1 > size2 ? size2 : size1
    for i in 1:last_i
        push!(result, let1[i], let2[i])
    end    
    if size1 > size2
        for i in last_i + 1:size1
            push!(result, let1[i])
        end
    else
        for i in last_i + 1:size2
            push!(result, let2[i])
        end    
    end
    return join(result, "");
end

tests = [["abcd", "1234"], ["abc", "12345"], ["abcde", "123"]]
for test in tests
    @printf "%-18s => " "$test"
    println(merge_strings(test[1], test[2]))
end

This program displays the following output:

$ julia ./merge-strings.jl
["abcd", "1234"]   => a1b2c3d4
["abc", "12345"]   => a1b2c345
["abcde", "123"]   => a1b2c3de

Wrapping up

The next week Perl Weekly Challenge will start soon. If you want to participate in this challenge, please check https://perlweeklychallenge.org/ and make sure you answer the challenge before 23:59 BST (British summer time) on February 25, 2024. And, please, also spread the word about the Perl Weekly Challenge if you can.

Leave a comment

About laurent_r

user-pic I am the author of the "Think Perl 6" book (O'Reilly, 2017) and I blog about the Perl 5 and Raku programming languages.