# 'Sort By' Function for Rebol

I'm looking for a more consise way to sort a block of objects. Where you can sort a block of blocks based on the numeric position of the values to compare, there's no such shorthand for comparing objects by a given field:

test-data: reduce [
object [name: "A" value: 1]
object [name: "B" value: 3]
object [name: "C" value: 2]
]


One solution would be to extend the native SORT function to accept a WORD! argument corresponding to the object field. However, that would require an update to the language and might take a little while to be accepted.

I've sketched out the following SORT-BY function that would take either a word (for the object field) or a block (an expression that is applied to the object):

sort-by: func [series [block!] comparator [block! word!]][
forskip series 2 [
insert series either word? comparator [
all [
in series/1 :comparator
get in series/1 :comparator
]
][
use [object] compose [
object: first series
(comparator)
]
]
]

sort/skip series 2

head forall series [remove series]
]


It's not ideal—it iterates through the block pulling the respective value from each object and adding it to the block; sorts the block; and removes the value again.

sort-by test-data 'value
sort-by test-data 'name
sort-by test-data [object/value]
sort-by test-data [sine 50 * object/value]


Any thoughts on the approach, particularly economy? Or even the need for such a function...

Obviously is lacking a descending/ascending switch—implied in future revision.

• "However, that would require an update to the language and is unlikely to be applied to Rebol 2 anyhow." There's a new drop of Rebol2 being made, 64-bit and such, you might mention it. :-) – HostileFork Dec 6 '14 at 19:42
• @HostileFork I put my head down for a few minutes and miss something as important as that! – rgchris Dec 6 '14 at 21:00

Any reason you can't use the SORTs /COMPARE refinement here?

Here is a working example of sort-by that uses it:

sort-by: function [
series     [block!]
comparator [block! word!]
][
sort/compare series func [a b] either word? comparator [
[a/:comparator < b/:comparator]
][
sortie: function [by] [
s: to-paren copy/deep comparator
forall s [
if all [path? s/1  s/1/1 = 'object] [s/1/1: by]
]
s
]

compose [(sortie 'a) < (sortie 'b)]
]
]

• I'm not opposed to SORT/COMPARE—indeed I wish this could just be written as sort/compare block-of-objects 'name—just not sure how fast/efficient it is compared to the above. Need some speed tests :) – rgchris Dec 18 '14 at 23:42
• What are the backticks for? – HostileFork Dec 19 '14 at 2:32
• @HostileFork Oh I put them in there to (help) avoid any possible name collisions (with func parameters) in something like a: 50 sort-by test-data [sine a * object/value]. Didn't test so perhaps not needed? – draegtun Dec 19 '14 at 9:33