jordan scales home twitter github
April 01, 2020

Hello, J! Sorting Some Strings

Following my previous (1) posts (2) on a fun little language called J (http://jsoftware.com/), I thought I'd do a quick writeup for some source code I provided in the Khan Academy Alumni slack channel.

(They're hiring! Stripe is too!)

Over the next few paragraphs we're going to sort some strings by length, and end up with a function that is 5 characters in length: \:#&> (really!)

   (\:#&>) ;: 'sorting strings by length'
┌───────┬───────┬──────┬──┐
│sorting│strings│lengthby│
└───────┴───────┴──────┴──┘

Boxes of strings

We can use the ;: Words verb to get a list of words in a string.

   'a'; 'tall'; 'cat'
┌─┬────┬───┐
│a│tall│cat│
└─┴────┴───┘
   ;: 'a tall cat'
┌─┬────┬───┐
│a│tall│cat│
└─┴────┴───┘

The fancy characters around each word represent the fact that they are "boxed."

We can > Open boxes.

   > ;: 'a tall cat'
a
tall
cat

We can get the number of items in a list (or a string - which is a list of characters) using the # Tally verb.

   # 1 3 5
3
   # 'hello'
5

We can compose these two operations with & Bond conjunction, which takes two verbs and returns a single verb.

   # & > ;: 'hello world'
5 5
   #&> ;: 'a tall cat'
1 4 3

Now we are able to get the number of characters in each string.

Sorting and ranking

\: Sort Down is a powerful verb which sorts the left argument using the right argument for scoring (in descending order).

For example, we can rearrange "hello" by giving l and h a score of 1 and 2 respectively, and giving e and o a score of 11 and 10 (respectively). e will then appear at the front of the result as it received the highest score.

   'hello' \: 1 11 2 2 10
eollh

We can use this to sort our list of words, using the length of each word as its score.

   #&> ;: 'a tall cat'
1 4 3
   (;: 'a tall cat') \: 1 4 3
┌────┬───┬─┐
│tall│cat│a│
└────┴───┴─┘
   (;: 'a tall cat') \: #&> ;: 'a tall cat'
┌────┬───┬─┐
│tall│cat│a│
└────┴───┴─┘

Making things shorter

We've successfully used the ;:, \:, #, &, and > operators to piece together a working sort mechanism, but there's one flaw - we have to repeat ;: 'a tall cat' twice 😱

To alleviate this, we can use one of J's strongest features, hooks.

In the following example, we'll take a list of numbers and add 7% to each of them. We may be inclined to write it like so:

   10 40 55 + 0.07&* 10 40 55
10.7 42.8 58.85

Which reads, take the list 10 40 55 and apply 0.07&* (remember bond?) to each item. Add the result to the list 10 40 55.

(Author's note: we also may be inclined to just multiply by 1.07 but that requires math).

Hooks allow us to simplify this by simply leaving off one of the arguments.

   (+ 0.07&*) 10 40 55
10.7 42.8 58.85

How does this work? J recognizes that we have two verbs within our parentheses (+ and 0.07&*) and combines them into a "hook." When we place a single argument at the end, J automatically applies it to both sides of the hook.

Put another way: (f g) x <=> x f g x for any two verbs f and g (don't forget your parentheses!)

So, the following expressions are equivalent:

   10 40 55 + 0.07&* 10 40 55
10.7 42.8 58.85
   (+ 0.07&*) 10 40 55
10.7 42.8 58.85

Let's circle back to our sorting mechanism before and see where we can apply this.

   (;: 'a tall cat') \: #&> ;: 'a tall cat'
┌────┬───┬─┐
│tall│cat│a│
└────┴───┴─┘

Spot it? Between our two instances of ;: 'a tall cat' we have two verbs: \: and #&>. Let's hook 'em.

   (\: #&>) ;: 'a tall cat'
┌────┬───┬─┐
│tall│cat│a│
└────┴───┴─┘

Lastly, we can eliminate some whitespace and build our custom verb.

   sort =. \:#&>
   sort ;: 'a tall cat'
┌────┬───┬─┐
│tall│cat│a│
└────┴───┴─┘

We did it!

I hope this was a decently short and pleasant introduction into some fun features of the J programming language:

I encourage you to download J and play around with it. Hooks and forks and other trains pop up in all sorts of places and may make you think differently about the code you write everyday.

Also consider following me on twitter.

Thanks for reading ✨