I’ve been doing the Weekly
Challenges. The
latest
involved list comparisons and rearangements. (Note that this ends
today.)
I'm bringing a new language on board… well, sort of.
Crystal is a compiled language that is
heavily inspired by, and broadly compatible with, Ruby. The aim is to
offer compiled-language speed but the more forgiving syntax of Ruby
compared with something like Rust or C. Let's see what happens.
Task 1: Magic Number
You are given two arrays of integers of same size, @x
and @y
.
Write a script to find the magic number that when added to each
elements of one of the array gives the second array. Elements order
is not important.
My thinking in this started with "oh, right, O(n²) comparison". But
with the constraint that this is transformation is a classical
function with domain and codomain, I realised that I only actually
need to look at one value in each array, because e.g. m +(min(x))
is
necessarily min(y)
.
So it turned into a one-liner. Python:
def magicnumber(a, b):
return min(b) - min(a)
Even in PostScript (though listmin
is a convenient shorthand method
for a call to my reduce
library function, since the built-in min
only takes two values).
/magicnumber {
listmin exch listmin sub
} bind def
Task 2: Number Game
You are given an array of integers, @ints
, with even number of
elements.
Write a script to create a new array made up of elements of the
given array. Pick the two smallest integers and add it to new array
in decreasing order i.e. high to low. Keep doing until the given
array is empty.
Again most of the solving is in the mental transformation, not in the
coding. Step one, sort the list. Step two, step forward and backwards,
picking elements 1, 0, 3, 2, 5, 4, etc.
Pulling two items off a list is something various languages approach
in different ways. Raku just lets you say "two things please", which
is easiest.
sub numbergame(@a0) {
my @out;
my @a = @a0.sort({$^a <=> $^b});
for @a -> $i, $j {
@out.push($j);
@out.push($i);
}
return @out;
}
Ruby has a function for it:
def numbergame(a0)
out = []
a = a0.sort
a.each_slice(2) do |s|
out.push(s[1])
out.push(s[0])
end
return out
end
and the only difference for Crystal is declaring out = Array(Int32).new
. Scala, Kotlin and Perl (with List::Utils
) also
take this approach, as does Python in the latest bleeding-edge version
(but not in Debian/stable's 3.11).
In Rust I get to play with iterators. (I think one could do something
with splitting and chaining but I didn't get it working.)
fn numbergame(a0: Vec<i32>) -> Vec<i32> {
let mut out = Vec::new();
let mut a = a0;
a.sort();
let mut ai = a.iter();
while let Some(i) = ai.next() {
out.push(*ai.next().unwrap());
out.push(*i);
}
out
}
My fallback is just to step through the list two indices at a time and
pull out values individually. In Lua here, but also JavaScript and
Python.
function numbergame(a0)
local out = {}
local a = a0
table.sort(a)
for i = 1, #a, 2 do
table.insert(out, a[i + 1])
table.insert(out, a[i])
end
return out
end
And finally in PostScript, where I already have a perfectly good
stack, so I just twiddle each chunk then rotate it to the bottom.
/numbergame {
0 dict begin
quicksort
[ exch
aload length /l exch def
l 2 idiv {
exch
l 2 roll
} repeat
]
end
} bind def
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.