Skip to content

Commit 206ed1c

Browse files
sbarzowskisparkprime
authored andcommitted
Change sort algorithm
Current std.sort implementation recurses may recurse N times for the array of size N. For example for sorted or reverse sorted data. This causes problems with std.set for example. This change implements mergesort which always divides the array in half, so the depth of recursion is always reasonable. For smaller arrays quicksort is still used (it is faster).
1 parent d1da227 commit 206ed1c

8 files changed

+71
-31
lines changed

benchmarks/bench.06.jsonnet

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// A benchmark for builtin sort
2+
3+
// TODO(sbarzowski) reverse functions should probably be a part of std
4+
local reverse(arr) =
5+
local l = std.length(arr);
6+
std.makeArray(l, function(i) arr[l - i - 1])
7+
;
8+
9+
local sort = std.sort;
10+
11+
true
12+
&& std.assertEqual(std.range(1, 500), sort(std.range(1, 500)))
13+
&& std.assertEqual(std.range(1, 1000), sort(std.range(1, 1000)))
14+
&& std.assertEqual(reverse(std.range(1, 1000)), sort(std.range(1, 1000), keyF=function(x) -x))
15+
&& std.assertEqual(std.range(1, 1000), sort(reverse(std.range(1, 1000))))
16+
&& std.assertEqual(std.makeArray(2000, function(i) std.floor((i + 2) / 2)), sort(std.range(1, 1000) + reverse(std.range(1, 1000))))

stdlib/std.jsonnet

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,17 +1132,41 @@ limitations under the License.
11321132
local bytes = std.base64DecodeBytes(str);
11331133
std.join('', std.map(function(b) std.char(b), bytes)),
11341134

1135-
// Quicksort
1135+
// Merge-sort for long arrays and naive quicksort for shorter ones
11361136
sort(arr, keyF=id)::
1137+
local quickSort(arr, keyF=id) =
1138+
local l = std.length(arr);
1139+
if std.length(arr) <= 1 then
1140+
arr
1141+
else
1142+
local pos = 0;
1143+
local pivot = keyF(arr[pos]);
1144+
local rest = std.makeArray(l - 1, function(i) if i < pos then arr[i] else arr[i + 1]);
1145+
local left = std.filter(function(x) keyF(x) < pivot, rest);
1146+
local right = std.filter(function(x) keyF(x) >= pivot, rest);
1147+
quickSort(left, keyF) + [arr[pos]] + quickSort(right, keyF);
1148+
1149+
local merge(a, b) =
1150+
local la = std.length(a), lb = std.length(b);
1151+
local aux(i, j, prefix) =
1152+
if i == la then
1153+
prefix + b[j:]
1154+
else if j == lb then
1155+
prefix + a[i:]
1156+
else
1157+
if keyF(a[i]) <= keyF(b[j]) then
1158+
aux(i + 1, j, prefix + [a[i]]) tailstrict
1159+
else
1160+
aux(i, j + 1, prefix + [b[j]]) tailstrict;
1161+
aux(0, 0, []);
1162+
11371163
local l = std.length(arr);
1138-
if std.length(arr) == 0 then
1139-
[]
1164+
if std.length(arr) <= 30 then
1165+
quickSort(arr, keyF=keyF)
11401166
else
1141-
local pivot = keyF(arr[0]);
1142-
local rest = std.makeArray(l - 1, function(i) arr[i + 1]);
1143-
local left = std.filter(function(x) keyF(x) < pivot, rest);
1144-
local right = std.filter(function(x) keyF(x) >= pivot, rest);
1145-
std.sort(left, keyF) + [arr[0]] + std.sort(right, keyF),
1167+
local mid = std.floor(l/ 2);
1168+
local left = arr[:mid], right = arr[mid:];
1169+
merge(std.sort(left, keyF=keyF), std.sort(right, keyF=keyF)),
11461170

11471171
uniq(arr, keyF=id)::
11481172
local f(a, b) =
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
RUNTIME ERROR: cannot test equality of functions
2-
std.jsonnet:1280:9-34 function <anonymous>
2+
std.jsonnet:1304:9-34 function <anonymous>
33
error.equality_function.jsonnet:17:1-33
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
RUNTIME ERROR: foobar
22
error.inside_equals_array.jsonnet:18:18-32 thunk <array_element>
3-
std.jsonnet:1260:29-33 thunk <b>
4-
std.jsonnet:1260:21-33 function <anonymous>
5-
std.jsonnet:1260:21-33 function <aux>
6-
std.jsonnet:1263:15-31 function <anonymous>
7-
std.jsonnet:1264:11-23
3+
std.jsonnet:1284:29-33 thunk <b>
4+
std.jsonnet:1284:21-33 function <anonymous>
5+
std.jsonnet:1284:21-33 function <aux>
6+
std.jsonnet:1287:15-31 function <anonymous>
7+
std.jsonnet:1288:11-23
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
RUNTIME ERROR: foobar
22
error.inside_equals_object.jsonnet:18:22-36 object <b>
3-
std.jsonnet:1274:50-54 thunk <b>
4-
std.jsonnet:1274:42-54 function <anonymous>
5-
std.jsonnet:1274:42-54 function <aux>
6-
std.jsonnet:1277:15-31 function <anonymous>
7-
std.jsonnet:1278:11-23
3+
std.jsonnet:1298:50-54 thunk <b>
4+
std.jsonnet:1298:42-54 function <anonymous>
5+
std.jsonnet:1298:42-54 function <aux>
6+
std.jsonnet:1301:15-31 function <anonymous>
7+
std.jsonnet:1302:11-23
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
RUNTIME ERROR: Object assertion failed.
22
error.invariant.equality.jsonnet:17:10-15 thunk <object_assert>
3-
std.jsonnet:1274:42-46 thunk <a>
4-
std.jsonnet:1274:42-54 function <anonymous>
5-
std.jsonnet:1274:42-54 function <anonymous>
6-
std.jsonnet:1278:11-23
3+
std.jsonnet:1298:42-46 thunk <a>
4+
std.jsonnet:1298:42-54 function <anonymous>
5+
std.jsonnet:1298:42-54 function <anonymous>
6+
std.jsonnet:1302:11-23
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
RUNTIME ERROR: Object assertion failed.
22
error.obj_assert.fail1.jsonnet:20:23-29 thunk <object_assert>
3-
std.jsonnet:1274:42-46 thunk <a>
4-
std.jsonnet:1274:42-54 function <anonymous>
5-
std.jsonnet:1274:42-54 function <anonymous>
6-
std.jsonnet:1278:11-23
3+
std.jsonnet:1298:42-46 thunk <a>
4+
std.jsonnet:1298:42-54 function <anonymous>
5+
std.jsonnet:1298:42-54 function <anonymous>
6+
std.jsonnet:1302:11-23
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
RUNTIME ERROR: foo was not equal to bar
22
error.obj_assert.fail2.jsonnet:20:32-65 thunk <object_assert>
3-
std.jsonnet:1274:42-46 thunk <a>
4-
std.jsonnet:1274:42-54 function <anonymous>
5-
std.jsonnet:1274:42-54 function <anonymous>
6-
std.jsonnet:1278:11-23
3+
std.jsonnet:1298:42-46 thunk <a>
4+
std.jsonnet:1298:42-54 function <anonymous>
5+
std.jsonnet:1298:42-54 function <anonymous>
6+
std.jsonnet:1302:11-23

0 commit comments

Comments
 (0)