summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Williams <nico@cryptonector.com>2014-09-30 21:49:37 -0500
committerNicolas Williams <nico@cryptonector.com>2014-09-30 21:52:30 -0500
commit4a57b84db03db7aee33c47ed6c7f6c1e648705fd (patch)
treed78fe18e46d8e7a9399966eb18eb81cd283d9832
parentf7a2af70526ab632008bb646d2b0e82f5c1724c9 (diff)
to_entries should not sort keys (fix #561)
-rw-r--r--builtin.c11
-rw-r--r--docs/content/3.manual/manual.yml6
-rw-r--r--jv.h1
-rw-r--r--jv_aux.c12
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));