Reputation: 757
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
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