Perl Weekly Challenge 233.
My solutions (task 1 and task 2 ) to the The Weekly Challenge - 233.
Task 1: Similar Words
Submitted by: Mohammad S Anwar
You are given an array of words made up of alphabets only.
Write a script to find the number of pairs of similar words. Two words are similar
if they consist of the same characters.
Example 1
Input: @words = ("aba", "aabb", "abcd", "bac", "aabc")
Output: 2
Pair 1: similar words ("aba", "aabb")
Pair 2: similar words ("bac", "aabc")
Example 2
Input: @words = ("aabb", "ab", "ba")
Output: 3
Pair 1: similar words ("aabb", "ab")
Pair 2: similar words ("aabb", "ba")
Pair 3: similar words ("ab", "ba")
Example 3
Input: @words = ("nba", "cba", "dba")
Output: 0
For each word I can make a canonical representation of its characters
and use a hash to count how many times N
it appears. The number of
pairs I can form from each set is the number of combinations of k
taken in groups of 2, k!/((k-2)! 2!)=k (k-1)/2
. The result is the sum of these numbers.
The code fits a two liner:
Example 1:
perl -MList::Util=uniq,sum0 -E '
$k{join "", sort {$a cmp $b} uniq split "", lc($_)}++ for (@ARGV);
say "@ARGV -> ", sum0 map {$k{$_}*($k{$_}-1)/2} grep {$k{$_}>1} keys %k;
' aba aabb abcd bac aabc
Results:
aba aabb abcd bac aabc -> 2
Example 2:
perl -MList::Util=uniq,sum0 -E '
$k{join "", sort {$a cmp $b} uniq split "", lc($_)}++ for (@ARGV);
say "@ARGV -> ", sum0 map {$k{$_}*($k{$_}-1)/2} grep {$k{$_}>1} keys %k;
' aabb ab ba
Results:
aabb ab ba -> 3
Example 3:
perl -MList::Util=uniq,sum0 -E '
$k{join "", sort {$a cmp $b} uniq split "", lc($_)}++ for (@ARGV);
say "@ARGV -> ", sum0 map {$k{$_}*($k{$_}-1)/2} grep {$k{$_}>1} keys %k;
' nba cba dba
Results:
nba cba dba -> 0
The full code follows:
1 # Perl weekly challenge 233
2 # Task 1: Similar Words
3 #
4 # See https://wlmb.github.io/2023/09/04/PWC233/#task-1-similar-words
5 use v5.36;
6 use List::Util qw(uniq sum0);
7 die <<~"FIN" unless @ARGV;
8 Usage: $0 w1 [w2...]
9 to count pairs of related words w1, w2, etc.
10 FIN
11 my %count;
12 # convert to lower case, split, find unique elements, sort them and join them
13 # to obtain unique representation of characters of word. Count how many appear.
14 $count{join "", sort {$a cmp $b} uniq split "", lc($_)}++ for (@ARGV);
15 my %pairs;
16 $pairs{$_}=$count{$_}*($count{$_}-1)/2 for grep {$count{$_}>=2} keys %count;
17 my $result=sum0 values %pairs;
18 say "@ARGV -> $result";
Examples:
./ch-1.pl aba aabb abcd bac aabc
./ch-1.pl aabb ab ba
./ch-1.pl nba cba dba
Results:
aba aabb abcd bac aabc -> 2
aabb ab ba -> 3
nba cba dba -> 0
Task 2: Frequency Sort
Submitted by: Mohammad S Anwar
You are given an array of integers.
Write a script to sort the given array in increasing order based on the
frequency of the values. If multiple values have the same frequency then
sort them in decreasing order.
Example 1
Input: @ints = (1,1,2,2,2,3)
Ouput: (3,1,1,2,2,2)
'3' has a frequency of 1
'1' has a frequency of 2
'2' has a frequency of 3
Example 2
Input: @ints = (2,3,1,3,2)
Ouput: (1,3,3,2,2)
'2' and '3' both have a frequency of 2, so they are sorted in decreasing order.
Example 3
Input: @ints = (-1,1,-6,4,5,-6,1,4,1)
Ouput: (5,-1,4,4,-6,-6,1,1,1)
I count how many times each input appears and use as the first part of a comparison routine for sorting the values. This fits a oneliner.
Example 1:
perl -E '
$c{$_}++ for @ARGV; say "@ARGV -> ", join " ", sort {$c{$a} <=> $c{$b} || $b <=> $a} @ARGV;
' 1 1 2 2 2 3
Results:
1 1 2 2 2 3 -> 3 1 1 2 2 2
Example 2:
perl -E '
$c{$_}++ for @ARGV; say "@ARGV -> ", join " ", sort {$c{$a} <=> $c{$b} || $b <=> $a} @ARGV;
' 2 3 1 3 2
Results:
2 3 1 3 2 -> 1 3 3 2 2
Example 3:
perl -E '
$c{$_}++ for @ARGV; say "@ARGV -> ", join " ", sort {$c{$a} <=> $c{$b} || $b <=> $a} @ARGV;
' -- -1 1 -6 4 5 -6 1 4 1
Results:
-1 1 -6 4 5 -6 1 4 1 -> 5 -1 4 4 -6 -6 1 1 1
The corresponding full code is:
1 # Perl weekly challenge 233
2 # Task 2: Frequency Sort
3 #
4 # See https://wlmb.github.io/2023/09/04/PWC233/#task-2-frequency-sort
5 use v5.36;
6 die <<~"FIN" unless @ARGV;
7 Usage: $0 N1 [N2...]
8 to sort the numbers Ni according to their frequencies (increasing)
9 and their values (decreasing).
10 FIN
11 my %count;
12 $count{$_}++ for @ARGV;
13 my @sorted=sort {$count{$a} <=> $count{$b} || $b <=> $a} @ARGV;
14 say "@ARGV -> @sorted";
Examples:
./ch-2.pl 1 1 2 2 2 3
./ch-2.pl 2 3 1 3 2
./ch-2.pl -1 1 -6 4 5 -6 1 4 1
Results:
1 1 2 2 2 3 -> 3 1 1 2 2 2
2 3 1 3 2 -> 1 3 3 2 2
-1 1 -6 4 5 -6 1 4 1 -> 5 -1 4 4 -6 -6 1 1 1