Advent Calendar 2022
| Day 9 | Day 10 | Day 11 |
The gift is presented by Bruce Gray
. Today he is talking about his solution to “The Weekly Challenge - 154”. This is re-produced for Advent Calendar 2022 from the original post by him.
In which we search for a needle in a lendee
(or maybe a chatchka in a haystack),
and delight in some lazy CPAN comfort.
TWC Task #1 - Missing Permutation
Find all permutations missing from a list.
- I have snipped most of the task permutations to make the code fit better in the blog post.
- I don't want to write my own permutation code again.
- Raku has built-in .permutations method, and (-) set-difference operator.
- Perl has several CPAN modules for permutations; List::Permutor is the first one Google returned, and its ->next method allowed me to write a loop that was different than my Raku solution.
- Python has Sets, and the itertools library handles permutations. itertools has lots of features that I miss when working outside of Raku, but they cannot be combined as nicely as Raku's, due to the basic(underlying(Python(function(call(syntax())))).
Raku
The partial list of juggled letters is in @in
.
my @in = <PELR PREL ...snip...
Take the first word; we could have used any of them.
With no argument, .comb splits into a list of single characters.
.permutations
gives all the possible rearrangements of those characters.
The ».
makes a hyper
method call that will be run on each item in the list of permuted characters, join
ing them back into words.
my @all = @in[0].comb.permutations».join;
When we do a set operation on a List
, it is automatically converted to a Set
.
(-)
is the ASCII
version of the set difference operator; it returns a Set of items present in the left-hand Set that are absent from the right-hand Set.
Iterating over the resulting Set gives us Pair
objects, where the .value is always True
, and the .key
is the part we are interested in.
say .key for @all (-) @in;
Perl
The Perl
version of Raku’s Set
is a hash,
initialized via my %h = map { $_ => 1 } @stuff;
.
use List::Permutor;
my @in = qw<PELR PREL ...snip...>;
my %in_set = map { $_ => 1 } @in;
my $permutor = List::Permutor->new( split '', $in[0] );
while ( my @letters = $permutor->next() ) {
my $word = join '', @letters;
say $word if not $in_set{$word};
}
Python
The Python
code mirrors the Perl solution. When given only a single string, list breaks it into characters.
In hindsight, I really should have named the last variable word instead of s
.
from itertools import permutations
input_words = "PELR PREL ...snip...".split()
input_set = set(input_words)
for i in permutations(list(input_words[0])):
s = "".join(i)
if s not in input_set:
print(s)
TWC Task #2 - Padovan Prime
Compute the first 10 distinct prime Padovan Numbers.
I don’t want to write my own is_prime() code again.
Raku
There were several ways to write the code block. I chose one that highlights $c being requested then deliberately unused.
.squish
only suppresses consecutive duplicates, so it works efficiently with lazy lists.
constant @Padovan = 1, 1, 1, { sink $^c; $^a + $^b } ... *;
say @Padovan.grep(&is-prime).squish.head(10);
Perl
I was very happy to discover List::Lazy, which make easy both the generation of the Padovan Numbers
, and filtering them for primes.
It was going to be more trouble than it was worth to make a version of Raku’s .squish
that would work with List::Lazy
, so I used the foreknowledge that there is exactly one duplicate, and just called uniq
on the 10+1
numbers returned by ->next
.
use List::Util qw<uniq head>;
use List::Lazy qw<lazy_list>;
use ntheory qw<is_prime>;
my $Padovan = lazy_list {
push @$_, $_->[-2] + $_->[-3];
shift @$_;
} [1, 1, 1];
my $prime_pad = $Padovan->grep( sub { is_prime($_) } );
say join ', ', uniq $prime_pad->next(11);
Python
I am pleased with the brevity of the Padovan()
generator.
head()
is from an itertools
recipe; it is not my own code.
Comparing the final print line to the second line of the Raku
code makes me wish for Raku’s flexibility of choosing method calls
vs function calls
.
from sympy import isprime
from itertools import islice
def Padovan():
p = [1, 1, 1]
while True:
p.append(p[-2] + p[-3])
yield p.pop(0)
def squish(a):
last = None
for i in a:
if i != last:
yield i
last = i
def head(n, iterable):
return list(islice(iterable, n))
print(head(10, squish(filter(isprime, Padovan()))))
Primes, Primes, everywhere a Prime.
Making all the Integers, alone or combined
Sieve N, to the square root.
Can't you see its Prime?
If you have any suggestion then please do share with us perlweeklychallenge@yahoo.com.