Perl weekly challenge 206

Shortest Time

Task

You are given a list of time points, at least 2, in the 24-hour clock format HH:MM.

Write a script to find out the shortest time in minutes between any two time points.

Solution

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#!/usr/bin/env raku

use v6.d;

constant $time-format = /
    $<hours>=(\d ** 2)
    :
    $<minutes>=(\d ** 2)
/;

sub convert-to-minutes(Str $time --> Int) {
    $time ~~ $time-format or
        die "Time string not in the right format.\nExpected 'HH:MM' but got $time";
    $<hours> × 60 + $<minutes>;
}

sub time-difference(Str $time1, Str $time2 --> Int) {
    constant $minutes-of-a-day = 24 × 60;
    my Int $minutes1 = convert-to-minutes($time1);
    my Int $minutes2 = convert-to-minutes($time2);
    my Int $time-diff = abs($minutes1 - $minutes2);
    $time-diff < $minutes-of-a-day ÷ 2 ?? $time-diff !! $minutes-of-a-day - $time-diff
;
}

sub shortest-time(Str @times --> Int) {
    min(map({ time-difference(@_[0], @_[1]) }, @times.combinations(2)));
}

#| Run test cases
multi sub MAIN('test') {
    use Test;
    plan 3;

    is shortest-time(Array[Str].new(["00:00", "23:55", "20:00"])), 5,
        'works for ("00:00", "23:55", "20:00")';
    is shortest-time(Array[Str].new(["01:01", "00:50", "00:57"])), 4,
        'works for ("01:01", "00:50", "00:57")';
    is shortest-time(Array[Str].new(["10:10", "09:30", "09:00", "09:55"])), 15,
        'works for ("10:10", "09:30", "09:00", "09:55")';
}

#| Take user provided list like 1 2 2 3
multi sub MAIN(*@elements where @elements.elems  2 && all(@elements) ~~ $time-format) {
    my Str @str-elements = @elements;
    say shortest-time(@str-elements);
}

Discussion

Having to return the time difference in minutes hints that it might be a good idea to convert the time into minutes. The convert-to-minutes function does this using Raku’s powerful Regexes and named captures. Time differences of more than twelve hours are converted by subtracting them from 24 hours to get the smaller and desired time difference.

Having a function which calculates the difference for two times the rest is basic functional programming: mapping that function over all possible pairs and taking the minimum of the list.

Array Pairings

Task

You are given an array of integers having even number of elements..

Write a script to find the maximum sum of the minimum of each pairs.

Solution

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/usr/bin/env raku

use v6.d;

sub array-pairings(Int @array --> Int) {
    my Int @sorted-array = sort(@array);
    my Int @even-indices = grep({ $_ % 2 == 0 }, 0 ..^ @array.elems);
    return sum(@sorted-array[@even-indices]);
}

#| Run test cases
multi sub MAIN('test') {
    use Test;
    plan 2;

    is array-pairings(Array[Int].new([1, 2, 3, 4])), 4, 'works for (1, 2, 3, 4)';
    is array-pairings(Array[Int].new([0, 2, 1, 3])), 2, 'works for (0, 2, 1, 3)';
}

#| Take user provided list like 1 2 2 3
multi sub MAIN(*@elements where @elements.elems  2 &&
    all(@elements) % 2 == 0 && all(@elements) ~~ /^<[+-]>?<[0..9]>+$/) {
    my Int @int-elements = @elements;
    say array-pairings(@int-elements);
}

Discussion

After sorting the given list split it after every second element. Each of the resulting pairs returns it’s first element. This can be done more efficiently by selecting all elements at even indices (starting at 0). Having the list of numbers simply summing them up to calculate the requested value.

Related
Raku · Perl