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->?
Written on August 19, 2024