4
\$\begingroup\$

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.

asked Dec 6, 2014 at 18:13
\$\endgroup\$
2
  • \$\begingroup\$ "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. :-) \$\endgroup\$ Commented Dec 6, 2014 at 19:42
  • \$\begingroup\$ @HostileFork I put my head down for a few minutes and miss something as important as that! \$\endgroup\$ Commented Dec 6, 2014 at 21:00

1 Answer 1

3
\$\begingroup\$

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)]
 ]
]
answered Dec 18, 2014 at 17:43
\$\endgroup\$
3
  • \$\begingroup\$ 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 :) \$\endgroup\$ Commented Dec 18, 2014 at 23:42
  • \$\begingroup\$ What are the backticks for? \$\endgroup\$ Commented Dec 19, 2014 at 2:32
  • \$\begingroup\$ @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? \$\endgroup\$ Commented Dec 19, 2014 at 9:33

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.