diff --git a/doc/site/modules/core/list.markdown b/doc/site/modules/core/list.markdown index 959ff747..204ffa39 100644 --- a/doc/site/modules/core/list.markdown +++ b/doc/site/modules/core/list.markdown @@ -94,6 +94,29 @@ System.print(["a", "b", "c"].removeAt(1)) //> b It is a runtime error if the index is not an integer or is out of bounds. +### **sort**(), **sort**(comparer) + +Sorts the elements of a list in-place; altering the list. The default sort is implemented using the quicksort algorithm. + +
+var list = [4, 1, 3, 2].sort() +System.print(list) //> [1, 2, 3, 4] ++ +A comparison function `comparer` can be provided to customise the element sorting. The comparison function must return a boolean value specifying the order in which elements should appear in the list. + +The comparison function accepts two arguments `a` and `b`, two values to compare, and must return a boolean indicating the inequality between the arguments. If the function returns true, the first argument `a` will appear before the second `b` in the sorted results. + +A compare function like `{|a, b| true }` will always put `a` before `b`. The default compare function is `{|a, b| a < b }`. + +
+var list = [9, 6, 8, 7]
+list.sort {|a, b| a < b}
+System.print(list) //> [6, 7, 8, 9]
+
+
+It is a runtime error if `comparer` is not a function.
+
### **[**index**]** operator
Gets the element at `index`. If `index` is negative, it counts backwards from
diff --git a/src/vm/wren_core.wren b/src/vm/wren_core.wren
index c2d0af92..58033e7c 100644
--- a/src/vm/wren_core.wren
+++ b/src/vm/wren_core.wren
@@ -323,6 +323,41 @@ class List is Sequence {
return other
}
+ sort() { sort {|low, high| low < high } }
+
+ sort(comparer) {
+ if (!(comparer is Fn)) {
+ Fiber.abort("Comparer must be a function.")
+ }
+ quicksort_(0, count - 1, comparer)
+ return this
+ }
+
+ quicksort_(low, high, comparer) {
+ if (low < high) {
+ var p = partition_(low, high, comparer)
+ quicksort_(low, p - 1, comparer)
+ quicksort_(p + 1, high, comparer)
+ }
+ }
+
+ partition_(low, high, comparer) {
+ var p = this[high]
+ var i = low - 1
+ for (j in low..(high-1)) {
+ if (comparer.call(this[j], p)) {
+ i = i + 1
+ var t = this[i]
+ this[i] = this[j]
+ this[j] = t
+ }
+ }
+ var t = this[i+1]
+ this[i+1] = this[high]
+ this[high] = t
+ return i+1
+ }
+
toString { "[%(join(", "))]" }
+(other) {
diff --git a/src/vm/wren_core.wren.inc b/src/vm/wren_core.wren.inc
index 1feda8c9..4b706f42 100644
--- a/src/vm/wren_core.wren.inc
+++ b/src/vm/wren_core.wren.inc
@@ -325,6 +325,41 @@ static const char* coreModuleSource =
" return other\n"
" }\n"
"\n"
+" sort() { sort {|low, high| low < high } }\n"
+"\n"
+" sort(comparer) {\n"
+" if (!(comparer is Fn)) {\n"
+" Fiber.abort(\"Comparer must be a function.\")\n"
+" }\n"
+" quicksort_(0, count - 1, comparer)\n"
+" return this\n"
+" }\n"
+"\n"
+" quicksort_(low, high, comparer) {\n"
+" if (low < high) {\n"
+" var p = partition_(low, high, comparer)\n"
+" quicksort_(low, p - 1, comparer)\n"
+" quicksort_(p + 1, high, comparer)\n"
+" }\n"
+" }\n"
+"\n"
+" partition_(low, high, comparer) {\n"
+" var p = this[high]\n"
+" var i = low - 1\n"
+" for (j in low..(high-1)) {\n"
+" if (comparer.call(this[j], p)) { \n"
+" i = i + 1\n"
+" var t = this[i]\n"
+" this[i] = this[j]\n"
+" this[j] = t\n"
+" }\n"
+" }\n"
+" var t = this[i+1]\n"
+" this[i+1] = this[high]\n"
+" this[high] = t\n"
+" return i+1\n"
+" }\n"
+"\n"
" toString { \"[%(join(\", \"))]\" }\n"
"\n"
" +(other) {\n"
diff --git a/test/core/list/sort.wren b/test/core/list/sort.wren
new file mode 100644
index 00000000..3c53660f
--- /dev/null
+++ b/test/core/list/sort.wren
@@ -0,0 +1,9 @@
+System.print([4, 1, 3, 2].sort()) // expect: [1, 2, 3, 4]
+
+var l = [10, 7, 8, 9, 1, 5]
+l.sort{|a, b| a < b }
+System.print(l) // expect: [1, 5, 7, 8, 9, 10]
+l.sort{|a, b| a > b }
+System.print(l) // expect: [10, 9, 8, 7, 5, 1]
+
+[10, 7, 8, 9, 1, 5].sort(3) // expect runtime error: Comparer must be a function.
\ No newline at end of file