Table of contents
Introduction
Uiua is an interesting new language. Strongly influenced by APL and BQN, it's array-oriented and stack-based. To explore it briefly, I will walk through my solutions to this week's Perl weekly challenge (242).
Uiua has an excellent language tour as well as a tutorial on its own site, which I'd recommend you go through if you're just starting out. I'm going to assume you have at least some syntactic familiarity with the language already.
Task 2
We'll actually start with Task 2 this week, since it's way easier.
Here is the problem description:
You are given `n x n` binary matrix.
Write a script to flip the given matrix as below.
1 1 0
0 1 1
0 0 1
a) Reverse each row
0 1 1
1 1 0
1 0 0
b) Invert each member
1 0 0
0 0 1
0 1 1
We'll start by putting the example matrix on the stack, in Uiua notation
[[1 1 0] [0 1 1] [0 0 1]]
giving
╭─
╷ 1 1 0
0 1 1
0 0 1
╯
Reversing each row can by done by a combination of the ≡ rows
and ⇌ reverse
functions. Like this:
[[1 1 0] [0 1 1] [0 0 1]]
≡⇌
giving
╭─
╷ 0 1 1
1 1 0
1 0 0
╯
That takes care of part a). What we need to do now is just reverse each element. Since most simple functions in Uiua are pervasive, this is as simple as calling the ¬ not
function on our previous result. Like this:
[[1 1 0] [0 1 1] [0 0 1]]
¬ ≡⇌
giving
╭─
╷ 1 0 0
0 0 1
0 1 1
╯
which is the expected answer. In the task there were two additional examples:
Example 1
Input: @matrix = ([1, 1, 0], [1, 0, 1], [0, 0, 0])
Output: ([1, 0, 0], [0, 1, 0], [1, 1, 1])
Example 2
Input: @matrix = ([1, 1, 0, 0], [1, 0, 0, 1], [0, 1, 1, 1], [1, 0, 1, 0])
Output: ([1, 1, 0, 0], [0, 1, 1, 0], [0, 0, 0, 1], [1, 0, 1, 0])
Let's put our logic in a function:
FlipMatrix ← ¬≡⇌
and add these examples as unit tests by combining ⍤ assert
and ≍ match
in a --- test scope
:
---
FlipMatrix [[1 1 0] [1 0 1] [0 0 0]]
⍤. ≍[[1 0 0] [0 1 0] [1 1 1]]
FlipMatrix [[1 1 0 0] [1 0 0 1] [0 1 1 1] [1 0 1 0]]
⍤. ≍[[1 1 0 0] [0 1 1 0] [0 0 0 1] [1 0 1 0]]
---
Both unit tests pass, so we are done with Task 2.
Task 1
Let's move on to the more challenging task of the two. Here is the problem description:
You are given two arrays of integers.
Write a script to find out the missing members in each other arrays.
Let's start with the first example.
Example 1
Input: @arr1 = (1, 2, 3)
@arr2 = (2, 4, 6)
Output: ([1, 3], [4, 6])
(1, 2, 3) has 2 members (1, 3) missing in the array (2, 4, 6).
(2, 4, 6) has 2 members (4, 6) missing in the array (1, 2, 3).
Since we'll be working with these example arrays a lot, let's start by putting them into variables a
and b
:
a ← [1 2 3]
b ← [2 4 6]
To get what members are common between the two arrays we can use ∊ member
like this:
∊ a b
which gives us a filter mask with 1s corresponding to the common elements:
[0 1 0]
We want the missing ones (i.e. the not common elements), so we invert this array with ¬ not
:
¬∊ a b
giving
[1 0 1]
We can now apply this inverted mask to our original array using ▽ keep
to get the missing members
¬∊ a b
▽: a
giving
[1 3]
which is correct. Note that this could also be put on a single line like this:
▽: a ¬∊ a b
We also need to do the opposite by reversing the arrays in our input
▽: b ¬∊ b a
giving
[4 6]
which is also correct. Since the output should be in the form of a single 2d array
Output: ([1, 3], [4, 6])
we could do it like this (variable names are case sensitive)
A = ▽: a ¬∊ a b
B = ▽: b ¬∊ b a
[A B]
or by using ⊟ couple
like this
A = ▽: a ¬∊ a b
B = ▽: b ¬∊ b a
⊟ A B
both giving the expected 2d array
╭─
╷ 1 3
4 6
╯
Let's try to do away with some repetition. We'll start by creating a single function that gets us the missing members in one direction between two arrays:
F ← ▽¬∊,
And combining them with ⊟ couple
⊟ F b a F a b
Note that this is equal to
⊟ F : a b F a b
Now things start to get interesting. Notice the symmetry, where we do two different operations to the same set of values. Uiua has a couple interesting functions for doing that, in this case we'll use ⊃ fork
:
⊟ ⊃(F∶)(F) a b
still giving us what we want
╭─
╷ 1 3
4 6
╯
So far so good.
Example 2
Input: @arr1 = (1, 2, 3, 3)
@arr2 = (1, 1, 2, 2)
Output: ([3])
(1, 2, 3, 3) has 2 members (3, 3) missing in the array (1, 1, 2, 2). Since they are same, keep just one.
(1, 1, 2, 2) has 0 member missing in the array (1, 2, 3, 3).
If we try our last function on this new data
a ← [1 2 3 3]
b ← [1 1 2 2]
F ← ▽¬∊,
⊟⊃(F∶)(F) a b
we get an error
Error: Cannot couple arrays with shapes [2] and [0]
at 4:1
4 | ⊟ ⊃(F∶)(F) a b
─
This is because arrays in Uiua must have a uniform shape, i.e. the same number of elements/rows/subarrays at each level. The solution is to □ box
the result of F
:
⊟⊃(□F∶)(□F) a b
giving
[⟦3 3⟧ ⟦⟧]
Notice the ⟦⟧
meaning it's a boxed array. There are two problems left to solve here though. First we want to get rid of the duplicate 3 in the first box. We'll use ⊝ deduplicate
for that:
⊟⊃(□⊝F∶)(□⊝F) a b
which works as expected
[⟦3⟧ ⟦⟧]
We also want to get rid of the empty second box altogether. We can do that by taking the ⧻ length
of each row and then ▽ keep
the ones >0
:
▽>0≡⧻. ⊟ ⊃(□⊝F∶)(□⊝F) a b
giving us
[⟦3⟧]
which is correct! Putting it altogether, we can inline F
for brevity and add our two examples as unit tests:
MissingMembers ← ▽>0≡⧻. ⊟⊃(□⊝▽¬∊,∶)(□⊝▽¬∊,)
---
⍤. ≍{[1 3][4 6]} MissingMembers [1 2 3] [2 4 6]
⍤. ≍{[3]} MissingMembers [1 2 3 3] [1 1 2 2]
---
The unit tests pass and we're happy once again!
Was it hard or easy to follow along? Do you want more content like this? Leave a comment!
Top comments (0)