Provide built-in function to help sort composite values
While we have the sort built-in function to sort a list of values by their "natural" order (as defined here) I have found that in the few cases where I've needed to sort a list of objects by the value of some key, that's really hard to do in Rego. A generic reduce function would make this easy for sure, but since that's been going nowhere, I propose we add a new built-in function to cover more than the most basic sorting needs.
Example code:
s := sort([
{"b": 1, "t": 100},
{"a": 1, "t": 50},
{"c": 1, "t": 80},
])
This will sort the list in the order of the a, b and c keys, while what I need is to sort the list in the order of the t values (ascending/descending doesn't matter).
Extracting these values and having them sorted is of course trivial, but I'm not interested in sorting the values but the full objects based on those values.
There could be many ways to accomplish this, and discussion around the best approach would be great! But just to provide an example from a current built-in function, I could imagine something like the object.get semantics, where the collection is provided along with a path (or possibly multiple paths?) to use for sorting:
s := sort_by(
[
{"b": 1, "t": 100},
{"a": 1, "t": 50},
{"c": 1, "t": 80},
],
["t"]
)
Which would allow also for nested attributes to be used as sort keys. The function should accept either an array or a set, and always return an array. If an object in the collection doesn't have the sorting key(s), it could either be omitted from the result, or be an error/undefined.
Just a thought, we could mimic SQL:
s := sort_by(stuff, {
"by": ["t", "s"], # optionally multiple things? i.e. sort by t first, then s
"order": "desc", # or "asc"
"limit": 10, # return top 10 only
})
I might be overthinking this 😅
No, I like it! I would prefer having an official / generic construct for LIMIT (and I think we have an issue open for that somewhere) but this would be a good start :) If we want to allow multiple sort keys, I guess we'd have to accept multiple arrays?
s := sort_by(stuff, {
"by": [["foo", "bar"], ["bar", "baz"]],
"order": "desc", # or "asc"
"limit": 10, # return top 10 only
})
But that would make the common case (a single key) a little more annoying to type. Perhaps it could be "an array of strings or an array of arrays"
Why not go all-in?
Perhaps it could be "an array of strings or an array of arrays"
| type | example | meaning |
|---|---|---|
| string | "foo" | sort by obj.foo |
| array | ["foo", "bar"] | sort by obj.foo.bar |
| array of arrays | [["foo", "bar"], ["bar", "baz"]] | sort by obj.foo.bar, then obj.bar.baz |
the only thing that is awkward is that there's no simple way to say "sort by obj.foo, then obj.bar", that would be [["foo"], ["bar"]] 🤔
That doesn't seem so awkward to me 🙂
This issue has been automatically marked as inactive because it has not had any activity in the last 30 days. Although currently inactive, the issue could still be considered and actively worked on in the future. More details about the use-case this issue attempts to address, the value provided by completing it or possible solutions to resolve it would help to prioritize the issue.