Magnus Markling

Posted on

# Uiua: Weekly challenge 242

## 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.

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
╯
``````

#### 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.

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.
``````

#### 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!