# Perl Weekly Challenge 265.

My solutions (task 1 and task 2 ) to the The Weekly Challenge - 265.

``````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  #
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
``````

``````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'
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:

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  #
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 -> ""
``````
Written on April 16, 2024