Make It Unique: Weekly Challenge #246
And now we’re on to Weekly Challenge #246! 246 is the product of 2, 3, and 41. It is Untouchable.
Task 1: 6 out of 49
Submitted by: Andreas Voegele
6 out of 49 is a German lottery.Write a script that outputs six unique random integers from the range 1 to 49.
Let’s Talk About It
I got this wrong on first pass.
“Six random integers”? That’s cake.
“Between the range of 1 and 49?” More cake.
The word I missed is “unique”. That’s the word that makes this work.
If you want to include all the input, use a for
loop, but if you’re concerned about the output, use a while
loop. Here, we’re watching the number of keys in the hash, so we’re randomizing a number, making it a key, and checking. The count doesn’t matter, so we set to 1
instead of incrementing. I mean, we could do that, but that makes a moving part that the next guy could get obsessed by. “Why increment?”
(Forgive me; I’ve been looking at something recently that I’m only 80% sure is someone using more shell than they understand, but trying to understand the possible cleverness in that 20%. Code, I believe, is like musical notation and mathematical expressions: most important as communication to others. When you write something ambiguous, you aren’t showing off cleverness, just writing something intentionally confusing for your colleagues.)
Show Me The Code
#!/usr/bin/env perl
use strict;
use warnings;
use experimental qw{ say postderef signatures state };
my %hash;
# Write a script that outputs six unique random integers
# from the range 1 to 49.
# I had missed 'unique', which means we have to be sure we
# deal with duplicates. Use the random number as keys to a hash
# and you won't get duplicates.
# Adding the numeric sort just makes it pretty.
while ( scalar keys %hash < 6 ) {
my $n = 1 + int rand 49;
$hash{$n} = 1;
}
say join "\n", sort { $a <=> $b } keys %hash;
# And here is my first pass, which ignored "unique".
# Because of that, it was very simple.
# say join "\n",
# sort { $a <=> $b } # and the example is sorted numerically, so we will
# map { 1 + int rand 49 } # which are random and between 1 and 49
# # but int rand ( n ) will give a number between 0 and n-1
# # so adding 1 will put it at the right range
# 1 .. 6; # we want six numbers
$ ./ch-1.pl
6
19
34
36
40
49
Task 2: Linear Recurrence of Second Order
Submitted by: Jorg Sommrey You are given an array @a of five integers.
Write a script to decide whether the given integers form a linear recurrence of second order with integer factors.
A linear recurrence of second order has the form
a[n] = p * a[n-2] + q * a[n-1] with n > 1
where p and q must be integers.
Let’s Talk About It
p
and q
must be integers, so we go through a lot of integers, do the math, and go next
to the outer loop if you find one. If there’s ever a case where, after a large array of integers, you don’t find something that matches, we return true.
First pass, I had two different loops for both p
and q
, for both 1..100
and -1, 1
, but it became much simpler when I rewrote for -100..100
. There’s no division to worry about.
And once you’ve sorted your $p
s and $q
s, it’s simple mathematics and named loops.
Show Me The Code
#!/usr/bin/env perl
use strict;
use warnings;
use experimental qw{ say postderef signatures state };
my @examples = (
[ 1, 1, 2, 3, 5 ],
[ 4, 2, 4, 5, 7 ],
[ 4, 1, 2, -3, 8 ],
);
for my $e (@examples) {
my $input = join ', ', $e->@*;
my $output = lrso( $e->@* );
say <<~"END";
Input: \$input = ($input)
Output: $output
END
}
sub lrso (@input) {
OUTER: for my $n ( 2 .. -1 + scalar @input ) {
for my $p ( -100 .. 100 ) {
my $pp = $p * $input[ $n - 2 ];
for my $q ( -100 .. 100 ) {
my $qq = $q * $input[ $n - 1 ];
my $rr = $pp + $qq;
next OUTER if $rr == $input[$n];
}
}
return 'false';
}
return 'true';
}
$ ./ch-2.pl
Input: $input = (1, 1, 2, 3, 5)
Output: true
Input: $input = (4, 2, 4, 5, 7)
Output: false
Input: $input = (4, 1, 2, -3, 8)
Output: true