From 3d5e68fc01e5c5a74f8fd3bdd02cea060e2d2444 Mon Sep 17 00:00:00 2001 From: Mat Mariani Date: Thu, 3 Dec 2020 14:59:07 -0500 Subject: [PATCH] Added List.sort(comp) to List module (#802) --- doc/site/modules/core/list.markdown | 23 +++++++++++++++++++ src/vm/wren_core.wren | 35 +++++++++++++++++++++++++++++ src/vm/wren_core.wren.inc | 35 +++++++++++++++++++++++++++++ test/core/list/sort.wren | 9 ++++++++ 4 files changed, 102 insertions(+) create mode 100644 test/core/list/sort.wren 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