sort_by and group_by functions, tests and docs.
This commit is contained in:
1 parent
ed7f95a492
commit
11965aaa2e
3 files changed
+96
No files matched your search
@@ -221,6 +221,26 @@ static jv f_sort(jv input){
|
||||
}
|
||||
}
|
||||
|
||||
static jv f_sort_by_impl(jv input, jv keys) {
|
||||
if (jv_get_kind(input) == JV_KIND_ARRAY &&
|
||||
jv_get_kind(keys) == JV_KIND_ARRAY &&
|
||||
jv_array_length(jv_copy(input)) == jv_array_length(jv_copy(keys))) {
|
||||
return jv_sort(input, keys);
|
||||
} else {
|
||||
return type_error2(input, keys, "cannot be sorted, as they are not both arrays");
|
||||
}
|
||||
}
|
||||
|
||||
static jv f_group_by_impl(jv input, jv keys) {
|
||||
if (jv_get_kind(input) == JV_KIND_ARRAY &&
|
||||
jv_get_kind(keys) == JV_KIND_ARRAY &&
|
||||
jv_array_length(jv_copy(input)) == jv_array_length(jv_copy(keys))) {
|
||||
return jv_group(input, keys);
|
||||
} else {
|
||||
return type_error2(input, keys, "cannot be sorted, as they are not both arrays");
|
||||
}
|
||||
}
|
||||
|
||||
static jv f_type(jv input) {
|
||||
jv out = jv_string(jv_kind_name(jv_get_kind(input)));
|
||||
jv_free(input);
|
||||
@@ -246,6 +266,8 @@ static struct cfunction function_list[] = {
|
||||
{(cfunction_ptr)f_type, "type", 1},
|
||||
{(cfunction_ptr)f_add, "add", 1},
|
||||
{(cfunction_ptr)f_sort, "sort", 1},
|
||||
{(cfunction_ptr)f_sort_by_impl, "_sort_by_impl", 2},
|
||||
{(cfunction_ptr)f_group_by_impl, "_group_by_impl", 2},
|
||||
};
|
||||
|
||||
static struct symbol_table cbuiltins = {function_list, sizeof(function_list)/sizeof(function_list[0])};
|
||||
@@ -271,6 +293,8 @@ static block bind_bytecoded_builtins(block b) {
|
||||
static const char* jq_builtins[] = {
|
||||
"def map(f): [.[] | f];",
|
||||
"def select(f): if f then . else empty end;",
|
||||
"def sort_by(f): _sort_by_impl(map([f]));",
|
||||
"def group_by(f): _group_by_impl(map([f]));",
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -487,6 +487,55 @@ sections:
|
||||
input: '[1, "1", [1]]'
|
||||
output: ['"1"', '"1"', '"[1]"']
|
||||
|
||||
- title: `sort, sort_by`
|
||||
body: |
|
||||
|
||||
The `sort` functions sorts its input, which must be an
|
||||
array. Values are sorted in the following order:
|
||||
|
||||
* `null`
|
||||
* `false`
|
||||
* `true`
|
||||
* numbers
|
||||
* strings, in alphabetical order (by unicode codepoint value)
|
||||
* arrays, in lexical order
|
||||
* objects
|
||||
|
||||
The ordering for objects is a little complex: first they're
|
||||
compared by comparing their sets of keys (as arrays in
|
||||
sorted order), and if their keys are equal then the values
|
||||
are compared key by key.
|
||||
|
||||
`sort_by` may be used to sort by a particular field of an
|
||||
object, or by applying any jq filter. `sort_by(foo)`
|
||||
compares two elements by comparing the result of `foo` on
|
||||
each element.
|
||||
|
||||
examples:
|
||||
- program: 'sort'
|
||||
input: '[8,3,null,6]'
|
||||
output: ['[null,3,6,8]']
|
||||
- program: 'sort_by(.foo)'
|
||||
input: '[{"foo":4, "bar":10}, {"foo":3, "bar":100}, {"foo":2, "bar":1}]'
|
||||
output: ['[{"foo":2, "bar":1}, {"foo":3, "bar":100}, {"foo":4, "bar":10}]']
|
||||
|
||||
- title: `group_by`
|
||||
body: |
|
||||
|
||||
`group_by(.foo)` takes as input an array, groups the
|
||||
elements having the same `.foo` field into separate arrays,
|
||||
and produces all of these arrays as elements of a larger
|
||||
array, sorted by the value of the `.foo` field.
|
||||
|
||||
Any jq expression, not just a field access, may be used in
|
||||
place of `.foo`. The sorting order is the same as described
|
||||
in the `sort` function above.
|
||||
|
||||
examples:
|
||||
- program: 'group_by(.foo)'
|
||||
input: '[{"foo":1, "bar":10}, {"foo":3, "bar":100}, {"foo":1, "bar":1}]'
|
||||
output: ['[[{"foo":1, "bar":10}, {"foo":1, "bar":1}], [{"foo":3, "bar":100}]]']
|
||||
|
||||
- title: `contains`
|
||||
body: |
|
||||
|
||||
@@ -583,6 +632,21 @@ sections:
|
||||
end
|
||||
input: 2
|
||||
output: ['"many"']
|
||||
|
||||
- title: `>, >=, <=, <`
|
||||
body: |
|
||||
|
||||
The comparison operators `>`, `>=`, `<=`, `<` return whether
|
||||
their left argument is greater than, greater than or equal
|
||||
to, less than or equal to or less than their right argument
|
||||
(respectively).
|
||||
|
||||
The ordering is the same as that described for `sort`, above.
|
||||
|
||||
examples:
|
||||
- program: '. < 5'
|
||||
input: 2
|
||||
output: ['true']
|
||||
|
||||
- title: and/or/not
|
||||
body: |
|
||||
|
||||
@@ -433,3 +433,11 @@ false
|
||||
sort
|
||||
[42,[2,5,3,11],10,{"a":42,"b":2},{"a":42},true,2,[2,6],"hello",null,[2,5,6],{"a":[],"b":1},"abc","ab",[3,10],{},false,"abcd",null]
|
||||
[null,null,false,true,2,10,42,"ab","abc","abcd","hello",[2,5,3,11],[2,5,6],[2,6],[3,10],{},{"a":42},{"a":42,"b":2},{"a":[],"b":1}]
|
||||
|
||||
(sort_by(.b) | sort_by(.a)), sort_by(.a, .b), sort_by(.b, .c), group_by(.b), group_by(.a + .b - .c == 2)
|
||||
[{"a": 1, "b": 4, "c": 14}, {"a": 4, "b": 1, "c": 3}, {"a": 1, "b": 4, "c": 3}, {"a": 0, "b": 2, "c": 43}]
|
||||
[{"a": 0, "b": 2, "c": 43}, {"a": 1, "b": 4, "c": 14}, {"a": 1, "b": 4, "c": 3}, {"a": 4, "b": 1, "c": 3}]
|
||||
[{"a": 0, "b": 2, "c": 43}, {"a": 1, "b": 4, "c": 14}, {"a": 1, "b": 4, "c": 3}, {"a": 4, "b": 1, "c": 3}]
|
||||
[{"a": 4, "b": 1, "c": 3}, {"a": 0, "b": 2, "c": 43}, {"a": 1, "b": 4, "c": 3}, {"a": 1, "b": 4, "c": 14}]
|
||||
[[{"a": 4, "b": 1, "c": 3}], [{"a": 0, "b": 2, "c": 43}], [{"a": 1, "b": 4, "c": 14}, {"a": 1, "b": 4, "c": 3}]]
|
||||
[[{"a": 1, "b": 4, "c": 14}, {"a": 0, "b": 2, "c": 43}], [{"a": 4, "b": 1, "c": 3}, {"a": 1, "b": 4, "c": 3}]]
|
||||
Reference in new issue
Block a user