Perl Weekly Challenge 234.
My solutions (task 1 and task 2 ) to the The Weekly Challenge - 234.
Task 1: Common Characters
Submitted by: Mohammad S Anwar
You are given an array of words made up of alphabetic characters only.
Write a script to return all alphabetic characters that show up in all
words including duplicates.
Example 1
Input: @words = ("java", "javascript", "julia")
Output: ("j", "a")
Example 2
Input: @words = ("bella", "label", "roller")
Output: ("e", "l", "l")
Example 3
Input: @words = ("cool", "lock", "cook")
Output: ("c", "o")
A solution may be found by preparing an array that stores for each word how many times each letter appears. Then, for each letter I can choose the minimum number of times it appears, and if positive, that is the number of times it should appear in the output. This yields a two liner.
Example 1:
perl -MList::Util=min -E 'for(@ARGV){my %l; $l{$_}++ for split ""; push @c, \%l;}
say "@ARGV -> ", join " ", map {$l=$_; ($l) x min map {$c[$_]{$l}} 0..@c-1} keys %{$c[0]}
' java javascript julia
Results:
java javascript julia -> j a
Example 2:
perl -MList::Util=min -E 'for(@ARGV){my %l; $l{$_}++ for split ""; push @c, \%l;}
say "@ARGV -> ", join " ", map {$l=$_; ($l) x min map {$c[$_]{$l}} 0..@c-1} keys %{$c[0]}
' bella label roller
Results:
bella label roller -> e l l
Example 3:
perl -MList::Util=min -E 'for(@ARGV){my %l; $l{$_}++ for split ""; push @c, \%l;}
say "@ARGV -> ", join " ", map {$l=$_; ($l) x min map {$c[$_]{$l}} 0..@c-1} keys %{$c[0]}
' cool lock cook
Results:
cool lock cook -> c o
The corresponding full code is:
1 # Perl weekly challenge 234
2 # Task 1: Common Characters
3 #
4 # See https://wlmb.github.io/2023/09/11/PWC234/#task-1-common-characters
5 use v5.36;
6 use List::Util qw(min);
7 die <<~"FIN" unless @ARGV;
8 Usage: $0 W1 [W2...]
9 to find the common characters in all words W1, W2...
10 FIN
11 my @letters_of_word;
12 for(@ARGV){
13 my %count_of_letter;
14 $count_of_letter{$_}++ for split "";
15 push @letters_of_word, \%count_of_letter;
16 }
17 my $number_of_words=@letters_of_word;
18 my @result=map {
19 my $letter=$_;
20 my $repetition=min map {
21 my $word_number=$_;
22 $letters_of_word[$word_number]{$letter}//0
23 } 0..$number_of_words-1;
24 ($letter) x $repetition;
25 } keys %{$letters_of_word[0]};
26 say "@ARGV -> @result";
Examples:
./ch-1.pl java javascript julia
./ch-1.pl bella label roller
./ch-1.pl cool lock cook
Results:
java javascript julia -> j a
bella label roller -> l l e
cool lock cook -> o c
Task 2: Unequal Triplets
Submitted by: Mohammad S Anwar
You are given an array of positive integers.
Write a script to find the number of triplets (i, j, k) that satisfies
num[i] != num[j], num[j] != num[k] and num[k] != num[i].
Example 1
Input: @ints = (4, 4, 2, 4, 3)
Ouput: 3
(0, 2, 4) because 4 != 2 != 3
(1, 2, 4) because 4 != 2 != 3
(2, 3, 4) because 2 != 4 != 3
Example 2
Input: @ints = (1, 1, 1, 1, 1)
Ouput: 0
Example 3
Input: @ints = (4, 7, 1, 10, 7, 4, 1, 1)
Output: 28
triplets of 1, 4, 7 = 3x2×2 = 12 combinations
triplets of 1, 4, 10 = 3×2×1 = 6 combinations
triplets of 4, 7, 10 = 2×2×1 = 4 combinations
triplets of 1, 7, 10 = 3x2x1 = 6 combinations
The last example gives a good hint for a solution. First, map each
number to the number of times it appears. Then, for each combination of
three distinct numbers, multiply the corresponding repetitions. Using sum0
and product
from List::Util
and combinations
from
Algorithm::Combinatorics
this yields a one liner.
Example 1:
perl -MAlgorithm::Combinatorics=combinations -MList::Util=sum0,product -E '
++$c{$_} for @ARGV; @n=keys %c; say "@ARGV -> ", @n<3?0:sum0 map {product @c{@$_}} combinations(\@n,3);
' 4 4 2 4 3
Results:
4 4 2 4 3 -> 3
Example 2:
perl -MAlgorithm::Combinatorics=combinations -MList::Util=sum0,product -E '
++$c{$_} for @ARGV; @n=keys %c; say "@ARGV -> ", @n<3?0:sum0 map {product @c{@$_}} combinations(\@n,3);
' 1 1 1 1 1
Results:
1 1 1 1 1 -> 0
Example 3:
perl -MAlgorithm::Combinatorics=combinations -MList::Util=sum0,product -E '
++$c{$_} for @ARGV; @n=keys %c; say "@ARGV -> ", @n<3?0:sum0 map {product @c{@$_}} combinations(\@n,3);
' 4 7 1 10 7 4 1 1
Results:
4 7 1 10 7 4 1 1 -> 28
The corresponding full code is:
1 # Perl weekly challenge 234
2 # Task 2: Unequal Triplets
3 #
4 # See https://wlmb.github.io/2023/09/11/PWC234/#task-2-unequal-triplets
5 use v5.36;
6 use Algorithm::Combinatorics qw(combinations);
7 use List::Util qw(sum0 product);
8 die <<~"FIN" unless @ARGV;
9 Usage: $0 N1 [N2...]
10 to count the number of unequal triplets in the set {N1 N2...}
11 FIN
12 my %count_for_number;
13 ++$count_for_number{$_} for @ARGV;
14 my @numbers=keys %count_for_number;
15 my $result=@numbers<3
16 ? 0
17 : sum0 map {
18 product @count_for_number{@$_}
19 } combinations(\@numbers,3);
20 say "@ARGV -> $result",
Examples:
./ch-2.pl 4 4 2 4 3
./ch-2.pl 1 1 1 1 1
./ch-2.pl 4 7 1 10 7 4 1 1
Results:
4 4 2 4 3 -> 3
1 1 1 1 1 -> 0
4 7 1 10 7 4 1 1 -> 28