Welcome to APL Quest#
Today’s Quest: Find the Mode#
Today’s quest focuses on finding the mode, which is the most frequently occurring element in a list. Let’s get started!
Test Data and Approach#
To find the most common element, there are various methods we could use. This time, we’ll explore a couple of them.
One approach is to remove one of each unique type of element until only one of each remains. The remaining element will be the most common because any elements that occur less frequently will have been removed in the process.
For our test data, let’s represent it as follows:
d ← (1 6 1 8 0 3 3 9 8) (2 7 1 8 2 8 1 8 2 8) (3 1 4 1 5)
Implementation Steps#
We’ll begin by writing a lambda function (or a small custom function) that we can apply to our data.
In APL, we have a function called unique
represented by the ≠
(not equal) sign. This function helps us create a mask: a boolean array indicating whether each element is the first of its kind.
Here’s an example using our test data. When we apply the unique function, we can identify the first occurrences:
{⍵/⍨(∧/m)≥m←⌽≠⌽⍵}⍣≡¨d
The output from the operation would be:
┌─────┬─┬─┐
│1 8 3│8│1│
└─────┴─┴─┘
This indicates that in the first dataset (1 6 1 8 0 3 3 9 8)
, the modes are 1
, 8
, and 3
.
Compressing the Data#
Using the slash
operator (/
), we can replicate our mask, removing the elements indicated by the mask. Since we need to discard the first occurrences, we’ll negate the mask.
To demonstrate this more effectively, we can use a nested function to further refine our results:
{⊃{⍺/⍨⍵=⌈/⍵}/,⌿,∘≢⌸⍵}¨d
This will yield the same result as previously shown:
┌─────┬─┬─┐
│1 8 3│8│1│
└─────┴─┴─┘
Iteration and Stability#
To ensure we find all modes, we may need to apply the function multiple times. Instead of a fixed number of iterations, we can apply the function until the output stabilizes.
To achieve this, we can define a custom function that continues applying the mask until subsequent runs yield the same results.
Handling Remaining Elements#
To enhance our function, we’ll introduce an approach that checks if every element is the first of its kind. We can achieve this by applying a logical AND reduction across the mask.
If there’s exactly one of each element remaining, we want to accelerate the stabilization process by returning a mask of all ones.
Final Adjustments for Order#
To maintain the original order of elements, we need to ensure the first occurrences removed are at the correct places. By reversing our mask for processing, we’ll keep the relative order intact.
Finally, we can refine this further into a clean, elegant solution—combining logic and APL functions to achieve our goal.
Using a High Order Function#
The key
function in APL will be our ally here. It allows us to derive a new function by combining two arguments and can compute the count of occurrences without needing to re-evaluate unique elements.
This efficiency can lead to a more streamlined analysis of the data. By applying the count
and unique
steps correctly, we can extract the modes swiftly and accurately.
Conclusion#
Through these steps, we have constructed an efficient APL function to determine the mode of a dataset. By utilizing various APL functions and logical constructs, we have maintained both accuracy and performance.
Thank you for participating in this APL Quest!