summary refs log tree commit diff
diff options
context:
space:
mode:
authorLeah Neukirchen <leah@vuxu.org>2023-01-02 21:35:29 +0100
committerLeah Neukirchen <leah@vuxu.org>2023-01-02 21:35:29 +0100
commit58f600a1bda649cf60568fd6c53784f035899d63 (patch)
tree16d0a79fe38f1856ccfe5600f4b8e266845f9d71
parent31afd1f7be00fbd28ea1c66ad9411d4fdf722ea7 (diff)
downloadmew-58f600a1bda649cf60568fd6c53784f035899d63.tar.gz
mew-58f600a1bda649cf60568fd6c53784f035899d63.tar.xz
mew-58f600a1bda649cf60568fd6c53784f035899d63.zip
add sort-by
-rw-r--r--mew.scm17
-rw-r--r--mew.svnwiki10
-rw-r--r--tests/test.mew4
3 files changed, 28 insertions, 3 deletions
diff --git a/mew.scm b/mew.scm
index d0de5e0..70bcff6 100644
--- a/mew.scm
+++ b/mew.scm
@@ -19,7 +19,7 @@
      per pop! prn proj push! puts
      rand range rep repeat
      sample scan scan-right sing? search seq set set-at sgn
-     shuffle shuffle! sort sort! str slurp
+     shuffle shuffle! sort sort-by sort! str slurp
      tally-accumulator tbl time
      while
      uniq-accumulator unlist until
@@ -1361,6 +1361,21 @@
                     (chicken-sort! xs less?)
                     (error "can only sort! vectors")))))
 
+  (define sort-by
+    (case-lambda
+      ((sequence transform) (sort-by sequence transform <?))
+      ((sequence transform less?)
+       (let ((t (tbl)))
+         (define (cached k)
+           (hash-table-ref t k
+                           (lambda ()
+                             (let ((v (transform k)))
+                               (hash-table-set! t k v)
+                               v))))
+         (sort sequence (lambda (a b)
+                          (less? (cached a) (cached b))))))))
+
+
   (let ((old-repl-prompt (repl-prompt)))
     (repl-prompt (lambda ()
                    (let ((old-prompt (old-repl-prompt)))
diff --git a/mew.svnwiki b/mew.svnwiki
index 2ac6cfe..d3adc99 100644
--- a/mew.svnwiki
+++ b/mew.svnwiki
@@ -384,13 +384,19 @@ It is an error to compare uncomparable values.
 
 <procedure>(sort <obj> [<less?>])</procedure>
 
-Sort the list/vector {{<obj>}} according to the relation {{less?}}
+Sort the list/vector {{<obj>}} according to the relation {{<less?>}}
 (by default: {{<?}}).
 
 <procedure>(sort! <obj> [<less?>])</procedure>
 
 Sort the vector {{<obj>}} destructively according to the relation
-{{less?}} (by default: {{<?}}).
+{{<less>?}} (by default: {{<?}}).
+
+<procedure>(sort-by <obj> <f> [<less?>])</procedure>
+
+Sort the items of the list/vector {{<obj>}} by their image under {{f}},
+according to the relation {{<less?>}} (by default: {{<?}}).
+This uses a Schwartzian transform and evaluates {{f}} only once per item.
 
 
 == Data types
diff --git a/tests/test.mew b/tests/test.mew
index ba9c223..13817b0 100644
--- a/tests/test.mew
+++ b/tests/test.mew
@@ -803,3 +803,7 @@
   (test #(1 2 3) (loc (v #(3 1 2)) (sort! v) v))
   (test #(3 2 1) (loc (v #(3 1 2)) (sort! v >) v))
   (test-error (sort! '(3 2 1))))
+
+(test-group "sort-by"
+  (test '("foobar" "zing" "baz") (sort-by '("foobar" "zing" "baz")
+                                          (op - (len _)))))