Perl Weekly Challenge 283.
My solutions (task 1 and task 2 ) to the The Weekly Challenge - 283.
Task 1: Unique Number
Submitted by: Mohammad Sajid Anwar
You are given an array of integers, @ints, where every elements appears more than once except
one element.
Write a script to find the one element that appears exactly one time.
Example 1
Input: @ints = (3, 3, 1)
Output: 1
Example 2
Input: @ints = (3, 2, 4, 2, 4)
Output: 3
Example 3
Input: @ints = (1)
Output: 1
Example 4
Input: @ints = (4, 3, 1, 1, 1, 4)
Output: 3
A straightforward approach would be to build a hash with the count for each element and then output that element that has a count of 1. The result fits a half-liner.
Example 1:
perl -E '
$c{$_}++ for @ARGV; $c{$_}==1&&say "@ARGV -> $_" for keys %c;
' 3 3 1
Results:
3 3 1 -> 1
Example 2:
perl -E '
$c{$_}++ for @ARGV; $c{$_}==1&&say "@ARGV -> $_" for keys %c;
' 3 2 4 2 4
Results:
3 2 4 2 4 -> 3
Example 3:
perl -E '
$c{$_}++ for @ARGV; $c{$_}==1&&say "@ARGV -> $_" for keys %c;
' 1
Results:
1 -> 1
Example 4:
perl -E '
$c{$_}++ for @ARGV; $c{$_}==1&&say "@ARGV -> $_" for keys %c;
' 4 3 1 1 1 4
Results:
4 3 1 1 1 4 -> 3
The full code is similar, but allows for the possibility of having arrays that are not fully conformant to the problem statement.
1 # Perl weekly challenge 283
2 # Task 1: Unique Number
3 #
4 # See https://wlmb.github.io/2024/08/19/PWC283/#task-1-unique-number
5 use v5.36;
6 die <<~"FIN" unless @ARGV;
7 Usage: $0 N1 N2...
8 to find which of the numbers N1 N2... appears only once.
9 FIN
10 my %count;
11 $count{$_}++ for @ARGV;
12 my @unique;
13 $count{$_}==1 && push @unique, $_ for keys %count;
14 say "@ARGV -> @unique";
Examples:
./ch-1.pl 3 3 1
./ch-1.pl 3 2 4 2 4
./ch-1.pl 1
./ch-1.pl 4 3 1 1 1 4
Results:
3 3 1 -> 1
3 2 4 2 4 -> 3
1 -> 1
4 3 1 1 1 4 -> 3
Other examples:
./ch-1.pl 1 1 1
./ch-1.pl 1 2 3
./ch-1.pl a b b c c
./ch-1.pl a b c
Task 2: Digit Count Value
Submitted by: Mohammad Sajid Anwar
You are given an array of positive integers, @ints.
Write a script to return true if for every index i
in the range 0 <= i < size of array, the digit i occurs
exactly the $ints[$i] times in the given array otherwise return false.
Example 1
Input: @ints = (1, 2, 1, 0)
Ouput: true
$ints[0] = 1, the digit 0 occurs exactly 1 time.
$ints[1] = 2, the digit 1 occurs exactly 2 times.
$ints[2] = 1, the digit 2 occurs exactly 1 time.
$ints[3] = 0, the digit 3 occurs 0 time.
Example 2
Input: @ints = (0, 3, 0)
Ouput: false
$ints[0] = 0, the digit 0 occurs 2 times rather than 0 time.
$ints[1] = 3, the digit 1 occurs 0 time rather than 3 times.
$ints[2] = 0, the digit 2 occurs exactly 0 time.
This seems to be tricky as it is not trivial to construct arrays which yield a true value. Each value plays a double role: as a repetition count and as a number that is being repeated. Thus, I expect there is a smart solution, maybe testing each n-element array against the few n-element arrays that fulfill the problem conditions (if any). However, a straightforward solution should also work, and I try it first. I make a hash to count how many times each number appears and then I check it is consistent with the value->repetitions rule. This yields a one-liner
Example 1:
perl -E '
$c{$_}++ for @ARGV; $o="True"; ($c{$_}==$ARGV[$_]) || ($o="False") for 0..@ARGV-1; say "@ARGV -> $o"
' 1 2 1 0
Results:
1 2 1 0 -> True
Example 2:
perl -E '
$c{$_}++ for @ARGV; $o="True"; ($c{$_}==$ARGV[$_]) || ($o="False") for 0..@ARGV-1; say "@ARGV -> $o"
' 0 3 0
Results:
0 3 0 -> False
The full code is similar.
1 # Perl weekly challenge 283
2 # Task 2: Digit Count Value
3 #
4 # See https://wlmb.github.io/2024/08/19/PWC283/#task-2-digit-count-value
5 use v5.36;
6 my %count;
7 $count{$_}++ for @ARGV;
8 my $result="True";
9 (($count{$_}//0)==$ARGV[$_]) || ($result="False") for 0..@ARGV-1;
10 say "@ARGV -> $result"
Example:
./ch-2.pl 1 2 1 0
./ch-2.pl 0 3 0
Results:
1 2 1 0 -> True
0 3 0 -> False
I can actually use the code above to generate all arrays below a given length which return a true value. There are indeed few of them. The following code is slow, as it generates and tests all possible sequences of the given lengths.
1 # Perl weekly challenge 283
2 # Task 2: Digit Count Value. Generate arrays
3 #
4 # See https://wlmb.github.io/2024/08/19/PWC283/#task-2-digit-count-value
5 use v5.36;
6 use Algorithm::Combinatorics qw(variations_with_repetition);
7 for my $length($ARGV[0]..$ARGV[1]){
8 my $iter=variations_with_repetition([0..$length-1], $length);
9 while(my $try=$iter->next){
10 say "@$try" if test($try);
11 }
12 }
13 sub test($array){
14 my @array=@$array;
15 my %count;
16 $count{$_}++ for @array;
17 my $result=1;
18 (($count{$_}//0)==$array[$_]) || ($result=0) for 0..@array-1;
19 $result
20 }
21
22
time ./ch-2a.pl 1 8
Results:
1 2 1 0
2 0 2 0
2 1 2 0 0
3 2 1 1 0 0 0
4 2 1 0 1 0 0 0
I may use these results to make a faster 1.5-liner:
perl -E '$k{$_}=1 for qw(1210 2020 21200 3211000 42101000);for(@ARGV){$o=$k{$_}?
"True":"False";$o="?" if length >8; say "$_->$o"}
' 1210 030 012345678
Results:
1210->True
030->False
012345678->?