Dan Oak
Dan Oak

Reputation: 757

How to Sort By using J

I'm used to sort by operation which many languages afford. It takes some comparator and sorts by it. What I want to do is to sort the following words firstly by length and then by letter order. Help me please.

I didn't find anything about it in Phrases or Dictionary on jsoftware, except from sorting and grading numerical values.

   words=: >;:'CLOUD USB NETWORK LAN SERVER FIREWIRE CLIENT PEER'
   ] alpha=: a. {~ (i.26) + a.i.'A'
ABCDEFGHIJKLMNOPQRSTUVWXYZ
   ;/ words/: alpha i. words
┌────────┬────────┬────────┬────────┬────────┬────────┬────────┬────────┐
│CLIENT  │CLOUD   │FIREWIRE│LAN     │NETWORK │PEER    │SERVER  │USB     │
└────────┴────────┴────────┴────────┴────────┴────────┴────────┴────────┘

My first crazy idea is to shift each word to right boundary of the array, e.g.

 ABC
DEFG
  XY

Then for whitespace assign the extreme ranking (in y argument of sorting primitive). And then shift each word back :D. It would be highly inefficient, I can't see another J-way.

Update
Here is the Wolfram Language code for my problem:

StringSplit @ "CLOUD USB NETWORK LAN SERVER FIREWIRE CLIENT PEER"
~SortBy~
(Reverse @ ComposeList[{StringLength}, #] &)

If I want to prioritize longer words, I just append Minus @* to StringLength. Basically my sorting order here is {{5, "CLOUD"}, {3, "USB"}, {7, "NETWORK"}, ...}.

I can make the same array in J using (,.~ #&.>) applied to boxed words, but how do I use sorting primitives then? Maybe this is the right first step? I'm still not sure, but it sound much better than my first guess :).

Upvotes: 2

Views: 149

Answers (1)

Michael Berry
Michael Berry

Reputation: 383

As requested, I have promoted answers suggested in the comments to the main body of the answer.

First of all, I don't think it is a good idea to apply > to the list of words because that will add fill which destroys information about the length of each word. So start with

   words=: ;:'CLOUD USB NETWORK LAN SERVER FIREWIRE CLIENT PEER'

Then you need a function foo that turns each word into a value that will sort in the order you wish using \: or /:

   words \: foo words

will do the trick. Or, depending on whether you think hooks are pretty or ugly, you could express that as

   (/: foo) words

My original suggestion for foo used #. to express each word as a single number:

   foo=: (128&#.)@(a.&i.)@>
   foo words
18145864388 1403330 345441182148939 1253582 2870553715410 39730390339053893 2322657797972 168911570

   (/: foo) words
┌───┬───┬────┬─────┬──────┬──────┬───────┬────────┐
│LAN│USB│PEER│CLOUD│CLIENT│SERVER│NETWORK│FIREWIRE│
└───┴───┴────┴─────┴──────┴──────┴───────┴────────┘

In a comment, Danylo Dubinin pointed out that instead of encoding the word, we can simply catenate the word length to the front of the index vector and sort using that:

   (/: (# , a.&i.)@>) words
┌───┬───┬────┬─────┬──────┬──────┬───────┬────────┐
│LAN│USB│PEER│CLOUD│CLIENT│SERVER│NETWORK│FIREWIRE│
└───┴───┴────┴─────┴──────┴──────┴───────┴────────┘

Upvotes: 1

Related Questions