From 4a57b84db03db7aee33c47ed6c7f6c1e648705fd Mon Sep 17 00:00:00 2001 From: Nicolas Williams Date: Tue, 30 Sep 2014 21:49:37 -0500 Subject: to_entries should not sort keys (fix #561) --- builtin.c | 11 ++++++++++- docs/content/3.manual/manual.yml | 6 +++++- jv.h | 1 + jv_aux.c | 12 ++++++++++++ 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/builtin.c b/builtin.c index 2426f6c9..65b6de6a 100644 --- a/builtin.c +++ b/builtin.c @@ -488,6 +488,14 @@ static jv f_keys(jq_state *jq, jv input) { } } +static jv f_keys_unsorted(jq_state *jq, jv input) { + if (jv_get_kind(input) == JV_KIND_OBJECT || jv_get_kind(input) == JV_KIND_ARRAY) { + return jv_keys_unsorted(input); + } else { + return type_error(input, "has no keys"); + } +} + static jv f_sort(jq_state *jq, jv input){ if (jv_get_kind(input) == JV_KIND_ARRAY) { return jv_sort(input, jv_copy(input)); @@ -860,6 +868,7 @@ static const struct cfunction function_list[] = { {(cfunction_ptr)f_tonumber, "tonumber", 1}, {(cfunction_ptr)f_tostring, "tostring", 1}, {(cfunction_ptr)f_keys, "keys", 1}, + {(cfunction_ptr)f_keys_unsorted, "keys_unsorted", 1}, {(cfunction_ptr)f_startswith, "startswith", 2}, {(cfunction_ptr)f_endswith, "endswith", 2}, {(cfunction_ptr)f_ltrimstr, "ltrimstr", 2}, @@ -965,7 +974,7 @@ static const char* const jq_builtins[] = { "def recurse: recurse(.[]?);", "def recurse_down: recurse;", - "def to_entries: [keys[] as $k | {key: $k, value: .[$k]}];", + "def to_entries: [keys_unsorted[] as $k | {key: $k, value: .[$k]}];", "def from_entries: map({(.key): .value}) | add | .//={};", "def with_entries(f): to_entries | map(f) | from_entries;", "def reverse: [.[length - 1 - range(0;length)]];", diff --git a/docs/content/3.manual/manual.yml b/docs/content/3.manual/manual.yml index 4e510f8d..d1996920 100644 --- a/docs/content/3.manual/manual.yml +++ b/docs/content/3.manual/manual.yml @@ -588,7 +588,7 @@ sections: input: '[[1,2], "string", {"a":2}, null]' output: [2, 6, 1, 0] - - title: "`keys`" + - title: "`keys`, `keys_unsorted`" body: | The builtin function `keys`, when given an object, returns @@ -603,6 +603,10 @@ sections: When `keys` is given an array, it returns the valid indices for that array: the integers from 0 to length-1. + The `keys_unsorted` function is just like `keys`, but if + the input is an object then the keys will not be sorted, + instead the keys will roughly be in insertion order. + examples: - program: 'keys' input: '{"abc": 1, "abcd": 2, "Foo": 3}' diff --git a/jv.h b/jv.h index 29738eda..465070ad 100644 --- a/jv.h +++ b/jv.h @@ -177,6 +177,7 @@ jv jv_setpath(jv, jv, jv); jv jv_getpath(jv, jv); jv jv_delpaths(jv, jv); jv jv_keys(jv /*object or array*/); +jv jv_keys_unsorted(jv /*object or array*/); int jv_cmp(jv, jv); jv jv_group(jv, jv); jv jv_sort(jv, jv); diff --git a/jv_aux.c b/jv_aux.c index dec5ce20..d859dc49 100644 --- a/jv_aux.c +++ b/jv_aux.c @@ -428,6 +428,18 @@ static int string_cmp(const void* pa, const void* pb){ return r; } +jv jv_keys_unsorted(jv x) { + if (jv_get_kind(x) != JV_KIND_OBJECT) + return jv_keys(x); + jv answer = jv_array_sized(jv_object_length(jv_copy(x))); + jv_object_foreach(x, key, value) { + answer = jv_array_append(answer, key); + jv_free(value); + } + jv_free(x); + return answer; +} + jv jv_keys(jv x) { if (jv_get_kind(x) == JV_KIND_OBJECT) { int nkeys = jv_object_length(jv_copy(x)); -- cgit v1.2.3