Perl Weekly Challenge 208

Mimimum Index Sum

Task

You are given two arrays of strings.

Write a script to find out all common strings in the given two arrays with minimum index sum. If no common strings found returns an empty list.

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
#!/usr/bin/env raku

use v6.d;

sub get-duplicates(Str @strings1, Str @strings2 --> List) {
    (Set(@strings1) (&) Set(@strings2)).keys.List;
}

sub invert-kv(Str @strings --> Hash) {
    (@strings.values Z=> @strings.keys).Hash;
}

sub index-sum(Str @strings1, Str @strings2 --> Seq) {
    my %invert1 = invert-kv(@strings1);
    my %invert2 = invert-kv(@strings2);
    my @duplicates = get-duplicates(@strings1, @strings2);
    map({ ($_, %invert1{$_} + %invert2{$_})}, @duplicates);
}

sub minimum-index-sum(Str @strings1, Str @strings2 --> Seq) {
    my @pairs = index-sum(@strings1, @strings2);
    my $min-index = min(map({ $_[1] }, @pairs));
    map({ $_[0] }, grep({ $_[1] == $min-index }, @pairs));
}

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

    is minimum-index-sum(Array[Str].new(['Perl', 'Raku', 'Love']),
        Array[Str].new(['Raku', 'Perl', 'Love'])).sort,
        ('Perl', 'Raku'),
        "works for ('Perl', 'Raku')";
    is minimum-index-sum(Array[Str].new(['A', 'B', 'C']),
        Array[Str].new(['D', 'E', 'F'])),
        (),
        'works for ()';
    is minimum-index-sum(Array[Str].new(['A', 'B', 'C']),
        Array[Str].new(['C', 'A', 'B'])),
        ('A'),
        'works for ("A")';
}

Discussion

Zip Metaoperator combined with the fat comma operator.

Duplicate and Missing

Task

You are given an array of integers in sequence with one missing and one duplicate.

Write a script to find the duplicate and missing integer in the given array. Return -1 if none found.

For the sake of this task, let us assume the array contains no more than one duplicate and missing.

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
#!/usr/bin/env raku

use v6.d;

sub get-duplicate(Int @numbers --> Int) {
    my %number-bag = Bag(@numbers);
    my $multiples = grep({ %number-bag{$_} > 1 }, %number-bag.keys);
    $multiples.elems == 1 ?? Int($multiples[0]) !! -1;
}

sub get-missing(Int @numbers --> Int) {
    my $set-difference = Set(@numbers[0] .. @numbers[* - 1]) (-) Set(@numbers);
    given $set-difference.elems {
        when 0 { return @numbers[* - 1] + 1 }
        when 1 { return $set-difference.keys[0] }
        default { return -1 }
    }
}

sub duplicate-and-missing(Int @numbers) {
    my Int @dam = (get-duplicate(@numbers), get-missing(@numbers));
    -1 (elem) @dam ?? -1 !! @dam;
}

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

    is duplicate-and-missing(Array[Int].new([1, 2, 2, 4])),
        (2, 3),
        "works for (1, 2, 2, 4)";
    is duplicate-and-missing(Array[Int].new([1, 2, 3, 4])),
        -1,
        "works for (1, 2, 3, 4)";
    is duplicate-and-missing(Array[Int].new([1, 2, 3, 3])),
        (3, 4),
        "works for (1, 2, 3, 3)";
}

#| Take user provided list like 1 2 2 3
multi sub MAIN(*@elements where @elements.elems  1 && all(@elements) ~~ /^0?<[1..9]><[0..9]>*$/) {
    my Int @int-elements = map({ $_.Int }, @elements);
    say "the result is { duplicate-and-missing(@int-elements) }"
}

Discussion

Related
Raku · Perl