Perl Weekly Challenge 261: Multiply by Two

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

Spoiler Alert: This weekly challenge deadline is due in a couple of days from now (on March 24, 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: Multiply by Two

You are given an array of integers, @ints and an integer $start.

Write a script to do the following:

a) Look for $start in the array @ints, if found multiply the number by 2

b) If not found stop the process otherwise repeat

In the end return the final value.

Example 1

Input: @ints = (5,3,6,1,12) and $start = 3
Output: 24

Step 1: 3 is in the array so 3 x 2 = 6
Step 2: 6 is in the array so 6 x 2 = 12
Step 3: 12 is in the array so 12 x 2 = 24

24 is not found in the array so return 24.

Example 2

Input: @ints = (1,2,4,3) and $start = 1
Output: 8

Step 1: 1 is in the array so 1 x 2 = 2
Step 2: 2 is in the array so 2 x 2 = 4
Step 3: 4 is in the array so 4 x 2 = 8

8 is not found in the array so return 8.

Example 3

Input: @ints = (5,6,7) and $start = 2
Output: 2

2 is not found in the array so return 2.

First, let's note that if $start is equal to 0 and if 0 is also found in the input array of integers, we will enter in an endless loop. We will add a condition to avoid that from happening.

Multiply by Two in Raku

In Raku, we will start by storing the input array of integers into a Bag, i.e. a collection of distinct objects with integer weights, to enable fast lookup. We could also have used a Set instead of a bag, since we don't really need integer weights, but a Bag is what came to my mind first. Then, we simply multiply $start by two until it is no longer found in the Bag.

sub multiply-by-two ($start is copy where * != 0, @in) {
    my $bag = @in.Bag;
    $start *= 2 while $bag{$start};
    return $start;
}

my @tests = (3, (5,3,6,1,12)), (1, (1,2,4,3)), (2, (5,6,7));
for @tests -> @test {
    printf "%d - %-15s => ", @test[0], "@test[1]";
    say multiply-by-two @test[0], @test[1];
}

This program displays the following output:

$ raku ./multiply-by-two.raku
3 - 5 3 6 1 12      => 24
1 - 1 2 4 3         => 8
2 - 5 6 7           => 2

Multiply by Two in Perl

This is a port to Perl of the above Raku program. Perl doesn't have Bags, but we can use a hash to the same effect.

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

sub multiply_by_two {
    my $start = shift;
    die "$start cannot be 0" if $start == 0;
    my %present = map { $_ => 1 } @_;
    $start *= 2 while $present{$start};
    return $start;
}

my @tests = ( [3, [5,3,6,1,12]], [1, [1,2,4,3]], [2, [5,6,7]] );
for my $test (@tests) {
    printf "%d - %-15s => ", $test->[0], "@{$test->[1]}";
    say multiply_by_two @$test[0], @{$test->[1]};
}

This program displays the following output:

$ raku ./multiply-by-two.raku
3 - 5 3 6 1 12      => 24
1 - 1 2 4 3         => 8
2 - 5 6 7           => 2

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 March 31, 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.