I’ve been doing the Weekly
Challenges. The
latest
involved array comparisons and date calculations. (Note that this is
open until 25 September 2022.)
Task 1: Unique Array
You are given list of arrayrefs.
Write a script to remove the duplicate arrayrefs from the given
list.
Removing duplicates from a list is a trivial task, but raw arrays
can't be used as hash keys. So I have to serialise them into a scalar
variable.
In Perl this is very straightforward with a core module:
use Storable qw(freeze);
sub uniquearray($n) {
my @o;
my %oh;
foreach my $i (@{$n}) {
Make the scalar version of the sublist.
my $ti = freeze($i);
If we haven't seen it before,
if (!exists $oh{$ti}) {
stick it on the output
push @o,$i;
and note that we have now seen it.
$oh{$ti} = 1;
}
}
return \@o;
}
(And most of the other languages have sets rather than using hashes.)
In Raku I don't have the Storable
module any more (as far as I can
see), but I do have the .raku()
method, which will produce a string
representation of a variable (the equivalent of Perl's
Data::Dumper
); I suspect parsing it would be slow, but I'm only
using this as a collision-free hash function, so I never have to
retrieve a value.
In Python I can convert the list to a tuple. In Rust everyone says
that serde
is what the cool kids use, so I serialise to a JSON
representation. Ruby has Marshal
and JavaScript has
JSON.Stringify
. Which just leaves three languages in which I had to
write my own serialiser: Kotlin has one but it's in the kotlinx
libraries which I can't readily add on the command line (largely
because documentation is very sparse; everyone assumes you're using an
IDE, or at least Gradle, and I suppose I really should try the
latter), and Lua and PostScript don't have them at all.
Task 2: Date Difference
You are given two dates, $date1
and $date2
in the format YYYY-MM-DD
.
Write a script to find the difference between the given dates in
terms of years and days only.
My approach here is to find the latest date with the month and day of
date1
that falls prior to date2
. The span of years from date1
to
that interstitial date is the years component; the span of days from
there to date2
is the days.
There is a problem with this algorithm: if date1
falls on 29
February and the interstitial date would fall in a non-leap-year, the
program will generate an invalid interstitial date. The behaviour in
this case is undefined anyway (what's the span from 2020-02-29 to
2021-03-01?), and fixing it would have taken effort, so I didn't.
I'm skipping Lua because of the lack of a native date library.
Rust with the chrono
library:
fn datedifference(d1s: &str, d2s: &str) -> [usize; 2] {
let mut d1 = NaiveDate::parse_from_str(d1s, "%Y-%m-%d").unwrap();
let mut d2 = NaiveDate::parse_from_str(d2s, "%Y-%m-%d").unwrap();
if d1 > d2 {
let t = d1;
d1 = d2;
d2 = t;
}
Get the year span assuming that d1's month and day are earlier in the
year than d2's, and construct the interstitial date.
let mut yd = d2.year() - d1.year();
let mut inter = NaiveDate::from_ymd(d2.year(), d1.month(), d1.day());
If that date is later in the year than d2 (this could also be done
as if inter > d2
).
if d1.month() > d2.month()
|| (d1.month() == d2.month() && d1.day() > d2.day())
{
then build the previous year's version instead, and reduce the year span.
inter = NaiveDate::from_ymd(d2.year() - 1, d1.month(), d1.day());
yd -= 1;
}
[yd.try_into().unwrap(), (d2 - inter).num_days().try_into().unwrap()]
}
I can't help noticing a great variation in verbosity: in Kotlin it's
var inter = LocalDate.of(d2.getYear(), d1.getMonthValue(), d1.getDayOfMonth())
while Python has the much more compact
inter = date(d2.year, d1.month, d1.day)
Full code on
github.
Comments on this post are now closed. If you have particular grounds for adding a late comment, comment on a more recent post quoting the URL of this one.