Repository: MiSawa/xq (rust)

Issue:
sort_by does not support multiple comparators
The `sort_by` filter of jq allows to specify multiple comparators in case the first one emits the same value.
```sh
 $ jq -nc '[{x:1,y:2},{x:2,y:2},{x:2,y:1},{x:1,y:1}] | sort_by(.x,.y)'
[{"x":1,"y":1},{"x":1,"y":2},{"x":2,"y":1},{"x":2,"y":2}]
 $ xq -nc '[{x:1,y:2},{x:2,y:2},{x:2,y:1},{x:1,y:1}] | sort_by(.x,.y)'
[1,2,1,2]
```

Pull request description:
Improve sort_by, min_by, max_by
This PR improves definitions of `sort_by`, `min_by`, and `max_by`. The `sort_by(f)` filter keeps the original order when `f` emits the same value. Also, fixes #40. The `{min,max}_by(f)` emits the element with {smaller,larger} index when `f` emits the same value.

Patch:
diff --git a/prelude.jq b/prelude.jq
index 16997e2..c250e53 100644
--- a/prelude.jq
+++ b/prelude.jq
@@ -61,9 +61,9 @@ def all(g; f): isempty(g | select(f | not));
 def all(f): all(.[]; f);
 def all: all(.);
 
-def sort_by(f): map([f, .]) | sort | map(.[1]);
-def min_by(f): def __yes_i_know_this_is_bad:.; sort_by(f)[0];
-def max_by(f): def __yes_i_know_this_is_bad:.; sort_by(f)[-1];
+def sort_by(f): [keys[] as $i | [[.[$i] | f], $i, .[$i]]] | sort | map(.[2]);
+def min_by(f): reduce (.[] | [[f], .]) as [$cmp, $val] (null; if . == null or .[0] >  $cmp then [$cmp, $val] end) | .[1];
+def max_by(f): reduce (.[] | [[f], .]) as [$cmp, $val] (null; if . == null or .[0] <= $cmp then [$cmp, $val] end) | .[1];
 def min: min_by(.);
 def max: max_by(.);
 def unique_by(f): def __yes_i_know_this_is_bad:.; [group_by(f)[] | .[0]];


Test patch:
diff --git a/tests/hand_written/mod.rs b/tests/hand_written/mod.rs
index 8779775..ea1c28c 100644
--- a/tests/hand_written/mod.rs
+++ b/tests/hand_written/mod.rs
@@ -648,3 +648,21 @@ test!(
     "Thu Mar  5 23:51:47 2015"
     "#
 );
+
+test!(
+    sort_by_min_by_max_by,
+    r#"
+    sort_by(.a), sort_by(.a,.b), min_by(.a), min_by(.a,.b), max_by(.a), max_by(.a,.b)
+    "#,
+    r#"
+    [{"a":2,"b":3},{"a":0,"b":2},{"a":2,"b":2},{"a":0,"b":1},{"a":1,"b":1}]
+    "#,
+    r#"
+    [{"a":0,"b":2},{"a":0,"b":1},{"a":1,"b":1},{"a":2,"b":3},{"a":2,"b":2}]
+    [{"a":0,"b":1},{"a":0,"b":2},{"a":1,"b":1},{"a":2,"b":2},{"a":2,"b":3}]
+    {"a":0,"b":2}
+    {"a":0,"b":1}
+    {"a":2,"b":2}
+    {"a":2,"b":3}
+    "#
+);