Perl Weekly Challenge 265.
My solutions (task 1 and task 2 ) to the The Weekly Challenge - 265.
Task 1: 33% Appearance
Submitted by: Mohammad Sajid Anwar
You are given an array of integers, @ints.
Write a script to find an integer in the given array that appeared 33%
or more. If more than one found, return the smallest. If none found then
return undef.
Example 1
Input: @ints = (1,2,3,3,3,3,4,2)
Output: 3
1 appeared 1 times.
2 appeared 2 times.
3 appeared 4 times.
3 appeared 50% (>33%) in the given array.
Example 2
Input: @ints = (1,1)
Output: 1
1 appeared 2 times.
1 appeared 100% (>33%) in the given array.
Example 3
Input: @ints = (1,2,3)
Output: 1
1 appeared 1 times.
2 appeared 1 times.
3 appeared 1 times.
Since all three appeared 33.3% (>33%) in the given array.
We pick the smallest of all.
I use a hash to count
appearances. I grep
the integers that appear more than a third of
the times and I use min
from List::Util
to choose the smallest
one. As division is not exact, I multiply
the number of appearances by three, instead of dividing the number of
integers by three. The result fits a one-liner.
Example 1:
perl -MList::Util=min -E '
$f{$_}++ for @ARGV; say "@ARGV -> ", min grep {3*$f{$_}>=@ARGV} keys %f;' 1 2 3 3 3 3 4 2
Results:
1 2 3 3 3 3 4 2 -> 3
Example 2:
perl -MList::Util=min -E '
$f{$_}++ for @ARGV; say "@ARGV -> ", min grep {3*$f{$_}>=@ARGV} keys %f;' 1 1
Results:
1 1 -> 1
Example 3:
perl -MList::Util=min -E '
$f{$_}++ for @ARGV; say "@ARGV -> ", min grep {3*$f{$_}>=@ARGV} keys %f;' 1 2 3
Results:
1 2 3 -> 1
The full code follows:
1 # Perl weekly challenge 265
2 # Task 1: 33% Appearance
3 #
4 # See https://wlmb.github.io/2024/04/16/PWC265/#task-1-33%-appearance
5 use v5.36;
6 use List::Util qw(min);
7 die <<~"FIN" unless @ARGV;
8 Usage: $0 N1 [N2...]
9 to find the smallest of the numbers N1... that appears
10 with a frequency of at least a third.
11 FIN
12 my %frequencies;
13 $frequencies{$_}++ for @ARGV;
14 say "@ARGV -> ", (min grep {3*$frequencies{$_}>=@ARGV} keys %frequencies) // "undef";
Examples:
./ch-1.pl 1 2 3 3 3 3 4 2
./ch-1.pl 1 1
./ch-1.pl 1 2 3
./ch-1.pl 1 2 3 4
Results:
1 2 3 3 3 3 4 2 -> 3
1 1 -> 1
1 2 3 -> 1
1 2 3 4 -> undef
Task 2: Completing Word
Submitted by: Mohammad Sajid Anwar
You are given a string, $str containing alphnumeric characters and
array of strings (alphabetic characters only), @str.
Write a script to find the shortest completing word. If none found
return empty string.
A completing word is a word that contains all the letters in the given
string, ignoring space and number. If a letter appeared more than once
in the given string then it must appear the same number or more in the word.
Example 1
Input: $str = 'aBc 11c'
@str = ('accbbb', 'abc', 'abbc')
Output: 'accbbb'
The given string contains following, ignoring case and number:
a 1 times
b 1 times
c 2 times
The only string in the given array that satisfies the condition is 'accbbb'.
Example 2
Input: $str = 'Da2 abc'
@str = ('abcm', 'baacd', 'abaadc')
Output: 'baacd'
The given string contains following, ignoring case and number:
a 2 times
b 1 times
c 1 times
d 1 times
The are 2 strings in the given array that satisfies the condition:
'baacd' and 'abaadc'.
Shortest of the two is 'baacd'
Example 3
Input: $str = 'JB 007'
@str = ('jj', 'bb', 'bjb')
Output: 'bjb'
The given string contains following, ignoring case and number:
j 1 times
b 1 times
The only string in the given array that satisfies the condition is 'bjb'.
I make a function that counts letters and ignores non-letters. I grep
all words by comparing
their letter counts to those of the initial string and I sort them by
length and, if necessary, alphabetically. The first word is then the
desired result. This yields a 2.5-liner
Example 1:
perl -MList::Util=all -E '
($s,@s)=@ARGV; %f=c($s); @v=sort {length $a <=> length $b || $a cmp $b} grep{my %c=c($_);
all {$c{$_} >= $f{$_}} keys %f}@s; say "str=\"$s\" arr=@s -> $v[0]"; sub c($w){my %c; $c{$_}++
for grep {/[a-z]/} split "",lc $w; %c}
' "aBc 11c" accbbb abc abbc
Results:
str="aBc 11c" arr=accbbb abc abbc -> accbbb
Example 2:
perl -MList::Util=all -E '
($s,@s)=@ARGV; %f=c($s); @v=sort {length $a <=> length $b || $a cmp $b} grep{my %c=c($_);
all {$c{$_} >= $f{$_}} keys %f}@s; say "str=\"$s\" arr=@s -> $v[0]"; sub c($w){my %c; $c{$_}++
for grep {/[a-z]/} split "",lc $w; %c}
' "Da2 abc" abcm baacd abaadc
Results:
str="Da2 abc" arr=abcm baacd abaadc -> baacd
Example 3:
perl -MList::Util=all -E '
($s,@s)=@ARGV; %f=c($s); @v=sort {length $a <=> length $b || $a cmp $b} grep{my %c=c($_);
all {$c{$_} >= $f{$_}} keys %f}@s; say "str=\"$s\" arr=@s -> $v[0]"; sub c($w){my %c; $c{$_}++
for grep {/[a-z]/} split "",lc $w; %c}
' "JB 007" jj bb bjb
Results:
str="JB 007" arr=jj bb bjb -> bjb
Another example:
perl -MList::Util=all -E '
($s,@s)=@ARGV; %f=c($s); @v=sort {length $a <=> length $b || $a cmp $b} grep{my %c=c($_);
all {$c{$_} >= $f{$_}} keys %f}@s; say "str=\"$s\" arr=@s -> $v[0]"; sub c($w){my %c; $c{$_}++
for grep {/[a-z]/} split "",lc $w; %c}
' "abc" abc bca cab
Results:
str="abc" arr=abc bca cab -> abc
The full code follows. I added some tests and print “” if there is no completing string.
1 # Perl weekly challenge 265
2 # Task 2: Completing Word
3 #
4 # See https://wlmb.github.io/2024/04/16/PWC265/#task-2-completing-word
5 use v5.36;
6 use List::Util qw(all);
7 die <<~"FIN" unless @ARGV;
8 Usage: $0 S [W1...]
9 to find the shortest completing word of string S among the words W1, W2...
10 FIN
11 my ($string, @words)=@ARGV;
12 my %frequencies = count_letters($string);
13 my @ordered= sort {length $a <=> length $b || $a cmp $b}
14 grep {
15 my %c=count_letters($_);
16 all {
17 ($c{$_}//0) >= $frequencies{$_}
18 }
19 keys %frequencies
20 } @words;
21 say "str=\"$string\" words=@words -> ", $ordered[0] // '""';
22 sub count_letters($word){
23 my %count;
24 $count{$_}++ for grep {/[a-z]/} split "",lc $word;
25 %count
26 }
Examples:
./ch-2.pl "aBc 11c" accbbb abc abbc
./ch-2.pl "Da2 abc" abcm baacd abaadc
./ch-2.pl "JB 007" jj bb bjb
./ch-2.pl "abc" abc bca cab
./ch-2.pl "abc" ab bc ca
Results:
str="aBc 11c" words=accbbb abc abbc -> accbbb
str="Da2 abc" words=abcm baacd abaadc -> baacd
str="JB 007" words=jj bb bjb -> bjb
str="abc" words=abc bca cab -> abc
str="abc" words=ab bc ca -> ""