Sorting
Sorting is good. Grading is better.
Sorting lists and tables
For list, dictionary or table x, and symbol vector c of column names
| direction | list | table |
|---|---|---|
| ascending | asc x |
c xasc x |
| descending | desc x |
c xdesc x |
return sorted lists, dictionaries and tables.
q)names:`jean`tom`khiloni`maria`raja`farokh`xin
q)scores:6 1 8 5 4 9 2
q)asc names
`s#`farokh`jean`khiloni`maria`raja`tom`xin
q)desc scores
9 8 6 5 4 2 1
q)desc names!scores
farokh | 9
khiloni| 8
jean | 6
maria | 5
raja | 4
xin | 2
tom | 1
q)`scores xdesc ([]names;scores)
names scores
--------------
farokh 9
khiloni 8
jean 6
maria 5
raja 4
xin 2
tom 1
Grading
Sorting a list is useful; grading it even more so.
Why?
Sorting a list returns it in sorted order. Grading it tells you the indexes to apply in order to sort it.
asc x <===> x iasc x
desc x <===> x idesc x
The intermediate step allows us to sort one list by the items in another: y idesc x.
q)names 3#idesc scores / gold, silver, bronze
`farokh`khiloni`jean
iasc and idesc) maps the raw list to the sorted one.
Grading returns a list of indices. The indices of a dictionary are its keys.
q)3#idesc names!scores / gold, silver, bronze
`farokh`khiloni`jean
Ranking
Ranking maps the sorted list back to the raw list: rank x tells you where each item of x appears in the sorted list.2
rank x <===> asc[x]?x
x <===> asc[x] rank x
q)([]names;scores;rnk:rank scores)
names scores rnk
------------------
jean 6 4
tom 1 0
khiloni 8 5
maria 5 3
raja 4 2
farokh 9 6
xin 2 1
rnk column shows each score’s position in the (ascending) sorted list.
rank x <===> iasc iasc x
Sortable
Data types 1–19 are all sortable.
Nested lists of uniform type1 are sorted into lexical order.
q)q:`sting`stole`stolen`steal`steel`stamp
q)asc string q
"stamp"
"steal"
"steel"
"sting"
"stole"
"stolen"
"s"), then their second items (all "t"), then their third items, and so on.
A symbol vector is sorted on the same principle.
q)string asc q
"stamp"
"steal"
"steel"
"sting"
"stole"
"stolen"
Sorting a general list
A general list is sorted first into atoms and lists; then by the types of its items; then within each type.
q)q:("foo";"bar";`baz;`sheep`cow`cat;`abc;42; 17;`hen`duck;3.14;0b;1b;0b;2022.09m)
q)1 type'\q
"foo" "bar" `baz `sheep`cow`cat `abc 42 17 `hen`duck 3.14 0b 1b 0b 2022.09m
10 10 -11 11 -11 -7 -7 11 -9 -1 -1 -1 -13
q)asc q
0b
0b
1b
17
42
3.14
`abc
`baz
2022.09m
"bar"
"foo"
`hen`duck
`sheep`cow`cat
"bar" and `hen`duck.
Grouping
List or dictionary
The result of group x is a dictionary with the nub (distinct items) of x as its key, and lists of indexes of x as its value.
q)group "mississippi"
m| ,0
i| 1 4 7 10
s| 2 3 5 6
p| 8 9
q)gold:0010010b / flag Gold Club members
q)group names!gold
0| `jean`tom`maria`raja`xin
1| `khiloni`farokh
Table by columns
Where
xis a tablecis a symbol atom or vector of colmn names ofx
then c xgroup x returns a keyed table (dictionary) of which the key is the nub of x`c and items of the other columns are lists of values for the rows which have that value for column/s c.
q)`gold xgroup ([]names;scores;gold)
gold| names scores
----| ----------------------------------
0 | `jean`tom`maria`raja`xin 6 1 5 4 2
1 | `khiloni`farokh 8 9
Exercises
No peeking.
Attempt each exercise before looking at its answer.
The exercises clarify your thinking. Reading answers does not.
-
Sort
names!scoresalphabetically by name.Answer
q)names!scores jean | 6 tom | 1 khiloni| 8 maria | 5 raja | 4 farokh | 9 xin | 2 q){x asc key x}names!scores / values in order of ascending keys 9 6 8 5 4 1 2 q){k!x k:asc key x}names!scores farokh | 9 jean | 6 khiloni| 8 maria | 5 raja | 4 tom | 1 xin | 2 -
How do
asc,desc,iasc, andidescsort a table?Answer
Keywords
asc,desc,iasc, andidescsort the first column of a table argument.q)desc ([]names;scores) names scores -------------- xin 2 tom 1 raja 4 maria 5 khiloni 8 jean 6 farokh 9 -
Messages are queued from your customers, but you must serve the Gold Club members first. Write an expression that returns customer names in the order that you will serve them.
q)([]names;gold) names gold ------------ jean 0 tom 0 khiloni 1 maria 0 raja 0 farokh 1 xin 0Answer
q)gold:0010010b q)([]names;gold) names gold ------------ jean 0 tom 0 khiloni 1 maria 0 raja 0 farokh 1 xin 0 q)idesc gold 2 5 0 1 3 4 6 q)names idesc gold `khiloni`farokh`jean`tom`maria`raja`xin -
Produce a table of scores as shown in Ranking but with the highest scores ranked top.
Answer
We saw
rank scoresgave us rankings for an ascending sort. We also saw thatrank xcould be replaced byiasc iasc x.q)([]names;scores;rnk:iasc idesc scores) names scores rnk ------------------ jean 6 2 tom 1 6 khiloni 8 1 maria 5 3 raja 4 4 farokh 9 0 xin 2 5 -
A perfect riffle shuffle divides a list into two equal parts, then interleaves consecutive items from each part. Write a riffle-shuffle function
rssuch thatq)rs "abcdef" "adbecf" q)rs til 6 0 3 1 4 2 5Answer
This is a classic APL phrase, written
The heart of it takes a boolean list the length of the argument{⍵[⍋⍋(⍴⍵)⍴0 1]}(⍴⍵)⍴0 1, grades it twice⍋⍋, and indexes the function argument⍵with that.In q:
The first application ofq){count[x]#01b}"abcdef" 010101b q){iasc count[x]#01b}"abcdef" 0 2 4 1 3 5iascreturns all the even indices followed by all the odd indices. (Notice that the sort is stable, so the even indices keep their order, as do the odds.)The second
iasctells us how to sort this list; i.e. pick the first, fourth, second, fifth, and so on.Indexingq){2 iasc/count[x]#01b}"abcdef" 0 3 1 4 2 5xwith that is the riffle shuffle.Of courseq){x 2 iasc/count[x]#01b}"abcdef" "adbecf"Soiasc iasc x <===> rank xq)rs:{x rank count[x]#01b} q)rs til 6 0 3 1 4 2 5 -
Explain the following.
q)group([]names;scores;gold) names scores gold| -------------------| - jean 6 0 | 0 tom 1 0 | 1 khiloni 8 1 | 2 maria 5 0 | 3 raja 4 0 | 4 farokh 9 1 | 5 xin 2 0 | 6Answer
The table
xis a list of like dictionaries, so its nub (distinct x) is also a list of like dictionaries, and thus also a table. So the key of the dictionary result ofgroup xis a table.The table contains no duplicates, so the nub is the entire table. The dictionary value is the list of indices for each row. Each row is unique, so:
q)q:([]names;scores;gold) q)group[q] ~ q!1#'til count q 1b -
Write a lambda3
fcthat returns a frequency count of the items of its argumentxas a dictionary in which the key is the distinct items ofxand the value is the number of times each key occurs inx. E.g.q)fc "mississippi" m| 1 i| 4 s| 4 p| 2Answer
q)group "mississippi" m| ,0 i| 1 4 7 10 s| 2 3 5 6 p| 8 9 q)fc:count each group :: / {count each group x} q)fc "mississippi" m| 1 i| 4 s| 4 p| 2