From 968c668ceed95810f9c2011495a60e2e30b90eab Mon Sep 17 00:00:00 2001 From: Justin Lin Date: Sun, 7 Feb 2021 12:13:32 +0800 Subject: [PATCH] by supports a function literal --- README.md | 2 +- docs/{lib2x-sort.md => lib3x-sort.md} | 11 +++++++---- src/util/_impl/_sort_impl.scad | 12 +++++++++++- src/util/sort.scad | 3 ++- test/util/test_sort.scad | 25 +++++++++++++++---------- 5 files changed, 36 insertions(+), 17 deletions(-) rename docs/{lib2x-sort.md => lib3x-sort.md} (59%) diff --git a/README.md b/README.md index ee6c8527..67362a02 100644 --- a/README.md +++ b/README.md @@ -139,7 +139,7 @@ These examples incubate dotSCAD and dotSCAD refactors these examples. See [examp - [util/parse_number](https://openhome.cc/eGossip/OpenSCAD/lib2x-parse_number.html) - [util/reverse](https://openhome.cc/eGossip/OpenSCAD/lib2x-reverse.html) - [util/slice](https://openhome.cc/eGossip/OpenSCAD/lib2x-slice.html) -- [util/sort](https://openhome.cc/eGossip/OpenSCAD/lib2x-sort.html) +- [util/sort](https://openhome.cc/eGossip/OpenSCAD/lib3x-sort.html) - [util/rand](https://openhome.cc/eGossip/OpenSCAD/lib2x-rand.html) - [util/fibseq](https://openhome.cc/eGossip/OpenSCAD/lib2x-fibseq.html) - [util/bsearch](https://openhome.cc/eGossip/OpenSCAD/lib2x-bsearch.html) diff --git a/docs/lib2x-sort.md b/docs/lib3x-sort.md similarity index 59% rename from docs/lib2x-sort.md rename to docs/lib3x-sort.md index 7a138178..bd0b27e7 100644 --- a/docs/lib2x-sort.md +++ b/docs/lib3x-sort.md @@ -2,14 +2,12 @@ Sorts the elements of a list in ascending order. The list is a list-of-list construct, such as `[[a0, a1, a2...], [b0, b1, b2,...], [c0, c1, c2,...],...]`. When sorting, the function looks only at one index position of each sublist. -From dotSCAD 2.3, when `by` is `"vt"`, it will sort points by zyx (from the last index to the first one). - **Since:** 2.0 ## Parameters - `lt` : The original list. -- `by` : Can be `"x"`、`"y"`、`"z"`, `"idx"` (Default) or `"vt"`. +- `by` : Can be `"x"`、`"y"`、`"z"`, or `"idx"` (Default). `"vt"`. From dotSCAD 2.3, when `by` is `"vt"`, it will sort points by zyx (from the last index to the first one). From dotSCAD 3.0, `by` supports a function literal that compares its two arguments for order. Returns a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second. - `idx` : When `by` is `"idx"`, the value of `idx` is used. The Default value is 0. ## Examples @@ -29,4 +27,9 @@ From dotSCAD 2.3, when `by` is `"vt"`, it will sort points by zyx (from the last assert( [[0, 2, 0], [0, 5, 0], [0, 7, 0], [0, 9, 0], [0, 10, 0]] == sort([[0, 10, 0], [0, 5, 0], [0, 7, 0], [0, 2, 0], [0, 9, 0]], by = "idx", idx = 1) - ); \ No newline at end of file + ); + + ascending = function(e1, e2) e1 - e2; + descending = function(e1, e2) e2 - e1; + assert(sort([2, 1, 3, 5, 4], by = ascending) == [1, 2, 3, 4, 5]); + assert(sort([2, 1, 3, 5, 4], by = descending) == [5, 4, 3, 2, 1]); \ No newline at end of file diff --git a/src/util/_impl/_sort_impl.scad b/src/util/_impl/_sort_impl.scad index d3b5f5ad..a6934a08 100644 --- a/src/util/_impl/_sort_impl.scad +++ b/src/util/_impl/_sort_impl.scad @@ -25,4 +25,14 @@ function _sort_by(lt, by, idx) = dict = [["x", 0], ["y", 1], ["z", 2], ["i", idx]], i = dict[search(by == "idx" ? "i" : by, dict)[0]][1] ) - _sort_by_idx(lt, i); \ No newline at end of file + _sort_by_idx(lt, i); + +function _sort_by_comp(lt, comp) = + let(leng = len(lt)) + leng <= 1 ? lt : + let( + pivot = lt[0], + before = [for(j = 1; j < leng; j = j + 1) if(comp(lt[j], pivot) < 0) lt[j]], + after = [for(j = 1; j < leng; j = j + 1) if(comp(lt[j], pivot) >= 0) lt[j]] + ) + concat(_sort_by_comp(before, comp), [pivot], _sort_by_comp(after, comp)); \ No newline at end of file diff --git a/src/util/sort.scad b/src/util/sort.scad index 507e47e2..8cb70c06 100644 --- a/src/util/sort.scad +++ b/src/util/sort.scad @@ -4,12 +4,13 @@ * @copyright Justin Lin, 2019 * @license https://opensource.org/licenses/lgpl-3.0.html * -* @see https://openhome.cc/eGossip/OpenSCAD/lib2x-sort.html +* @see https://openhome.cc/eGossip/OpenSCAD/lib3x-sort.html * **/ use <_impl/_sort_impl.scad>; function sort(lt, by = "idx", idx = 0) = + is_function(by) ? _sort_by_comp(lt, by) : // support function literal by == "vt" ? _vt_sort(lt) : // for example, sort by zyx for a list of points _sort_by(lt, by, idx); \ No newline at end of file diff --git a/test/util/test_sort.scad b/test/util/test_sort.scad index e45ab38a..262ec525 100644 --- a/test/util/test_sort.scad +++ b/test/util/test_sort.scad @@ -4,20 +4,25 @@ use ; module test_sort() { echo("==== test_sort ===="); - assertEqualPoints( - [[2, 0, 0], [5, 0, 0], [7, 0, 0], [9, 0, 0], [10, 0, 0]], + assert( + [[2, 0, 0], [5, 0, 0], [7, 0, 0], [9, 0, 0], [10, 0, 0]] == + sort([[10, 0, 0], [5, 0, 0], [7, 0, 0], [2, 0, 0], [9, 0, 0]]) + ); + + assert( + [[2, 0, 0], [5, 0, 0], [7, 0, 0], [9, 0, 0], [10, 0, 0]] == sort([[10, 0, 0], [5, 0, 0], [7, 0, 0], [2, 0, 0], [9, 0, 0]], by = "x") ); - assertEqualPoints( - [[2, 0, 0], [5, 0, 0], [7, 0, 0], [9, 0, 0], [10, 0, 0]], - sort([[10, 0, 0], [5, 0, 0], [7, 0, 0], [2, 0, 0], [9, 0, 0]], by = "idx", idx = 0) - ); - - assertEqualPoints( - [[0, 2, 0], [0, 5, 0], [0, 7, 0], [0, 9, 0], [0, 10, 0]], - sort([[0, 10, 0], [0, 5, 0], [0, 7, 0], [0, 2, 0], [0, 9, 0]], by = "y") + assert( + [[0, 2, 0], [0, 5, 0], [0, 7, 0], [0, 9, 0], [0, 10, 0]] == + sort([[0, 10, 0], [0, 5, 0], [0, 7, 0], [0, 2, 0], [0, 9, 0]], by = "idx", idx = 1) ); + + ascending = function(e1, e2) e1 - e2; + descending = function(e1, e2) e2 - e1; + assert(sort([2, 1, 3, 5, 4], by = ascending) == [1, 2, 3, 4, 5]); + assert(sort([2, 1, 3, 5, 4], by = descending) == [5, 4, 3, 2, 1]); } test_sort();