diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2025-03-27 19:31:08 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2025-03-27 19:31:08 -0700 |
commit | 48a7a911475fbeccc2e1fe078a5db1544909096b (patch) | |
tree | e78b01798fbfcdbfa2d5e34ac3242927cb451c0e | |
parent | b169d4699786762efc57e9a4b4ef72838002066e (diff) | |
download | txr-48a7a911475fbeccc2e1fe078a5db1544909096b.tar.gz txr-48a7a911475fbeccc2e1fe078a5db1544909096b.tar.bz2 txr-48a7a911475fbeccc2e1fe078a5db1544909096b.zip |
New function: remove.
We need a remove function that doesn't have an equality
suffix, analogous to member, pos, count.
* eval.c (eval_init): Register remove intrinsic.
* lib.[ch] (remov): New function.
Named this way to avoid clashing with the ISO C remove
function in <stdlib.h>.
* tests/012/seq.tl: New tests.
* txr.1: Documented.
-rw-r--r-- | eval.c | 1 | ||||
-rw-r--r-- | lib.c | 36 | ||||
-rw-r--r-- | lib.h | 1 | ||||
-rw-r--r-- | tests/012/seq.tl | 24 | ||||
-rw-r--r-- | txr.1 | 48 |
5 files changed, 105 insertions, 5 deletions
@@ -7480,6 +7480,7 @@ void eval_init(void) reg_fun(intern(lit("rmember"), user_package), func_n4o(rmember, 2)); reg_fun(intern(lit("member-if"), user_package), func_n3o(member_if, 2)); reg_fun(intern(lit("rmember-if"), user_package), func_n3o(rmember_if, 2)); + reg_fun(intern(lit("remove"), user_package), func_n5o(remov, 2)); reg_fun(intern(lit("remq"), user_package), func_n3o(remq, 2)); reg_fun(intern(lit("remql"), user_package), func_n3o(remql, 2)); reg_fun(intern(lit("remqual"), user_package), func_n3o(remqual, 2)); @@ -3506,6 +3506,42 @@ static val rem_impl(val (*eqfun)(val, val), val self, return seq_finish(&bu); } +val remov(val obj, val seq, val testfun_in, val keyfun_in, val mapfun_in) +{ + val self = lit("remove"); + val testfun = default_null_arg(testfun_in); + val keyfun = default_null_arg(keyfun_in); + val mapfun = default_null_arg(mapfun_in); + seq_iter_t it; + seq_build_t bu; + val elem; + + seq_iter_init(self, &it, seq); + seq_build_init(self, &bu, seq); + + if (!testfun && !keyfun && !mapfun) { + while (seq_get(&it, &elem)) { + if (!equal(obj, elem)) + seq_add(&bu, elem); + } + } else { + while (seq_get(&it, &elem)) { + val key = keyfun ? funcall1(keyfun, elem) : elem; + if ((testfun && !funcall2(testfun, obj, key)) || + (!testfun && !equal(obj, key))) + { + if (mapfun == keyfun) + elem = key; + else if (mapfun) + elem = funcall1(mapfun, elem); + seq_add(&bu, elem); + } + } + } + + return seq_finish(&bu); +} + static val rem_if_impl(val pred, val seq, val keyfun_in, val mapfun_in, val self) { @@ -886,6 +886,7 @@ val member(val item, val list, val testfun, val keyfun); val rmember(val item, val list, val testfun, val keyfun); val member_if(val pred, val list, val key); val rmember_if(val pred, val list, val key); +val remov(val item, val seq, val testfun_in, val keyfun_in, val mapfun_in); val remq(val obj, val seq, val keyfun); val remql(val obj, val seq, val keyfun); val remqual(val obj, val seq, val keyfun); diff --git a/tests/012/seq.tl b/tests/012/seq.tl index b1063513..d6c9af64 100644 --- a/tests/012/seq.tl +++ b/tests/012/seq.tl @@ -587,6 +587,30 @@ #(1 9 25 49 81 121 169 225 289 361))) (mtest + (remove 3 #(3)) #() + (remove 2 #(3)) #(3) + (remove 2 #(3 2 3)) #(3 3) + (remove 2 #(2 2 2)) #()) + +(mtest + (remove "b" '#"a b c") #"a c" + (remove "B" '#"a b c") #"a b c" + [remove "B" '#"a b c" tf] nil + [remove "B" '#"a b c" : upcase-str] #"a c" + [remove "B" '#"a b c" tf upcase-str] nil + [remove "B" '#"a b c" equal upcase-str upcase-str] #"A C" + [remove "b" '#"a b c" equal : upcase-str] #"A C") + +(mtest + (remove #\b "abc") "ac" + (remove #\B "abc") "abc" + [remove #\B "abc" tf] "" + [remove #\B "abc" : chr-toupper] "ac" + [remove #\B "abc" tf chr-toupper] "" + [remove #\B "abc" equal chr-toupper chr-toupper] "AC" + [remove #\b "abc" equal : chr-toupper] "AC") + +(mtest (flatten '()) () (flatten '(nil)) () (flatten '(a)) (a) @@ -36576,6 +36576,7 @@ is compared to .coNP Functions @, remove-if @, keep-if @, separate @ remove-if* and @ keep-if* .synb +.mets (remove < key < sequence >> [testfun >> [ keyfun <> [ mapfun ]]]) .mets (remove-if < predfun < sequence >> [ keyfun <> [ mapfun ]]) .mets (keep-if < predfun < sequence >> [ keyfun <> [ mapfun ]]) .mets (separate < predfun < sequence >> [ keyfun <> [ mapfun ]]) @@ -36583,15 +36584,26 @@ is compared to .mets (keep-if* < predfun < sequence >> [ keyfun <> [ mapfun ]]) .syne .desc +Functions in this group perform filtering of sequences, +either retaining or rejecting items which satisfy a condition, +or separating the two into two sequences. + The .code remove-if -function produces a sequence whose contents are those of +function produces a sequence whose elements are taken from .meta sequence -but with those elements removed which satisfy -.metn predfun . -Those elements which are not removed appear in the same order. +and which are are projected through +.metn mapfun , +if that argument is specified, or else taken as-is. +Elements which satisfy +.meta predfun +do not appear in the output sequence. + +Those elements which are retained appear in the same order. The result sequence may share substructure with the input sequence, -and may even be the same sequence object if no items are removed. +and may even be the same sequence object if no items are removed, +and no mapping is specified by +.metn mapfun . The optional .meta keyfun @@ -36625,6 +36637,32 @@ is called, or whether the result of is used. The +.code remove +function is similar to +.codn remove-if . +The condition identifying elements to be removed is specified not as a +.meta predfun +predicate, but as a +.meta key +element: elements are removed if they are the same as +.metn key . +Each element is projected to a key value through +.metn keyfun , +if that is specified, and then compared to the input +.meta key +using +.metn testfun . +If +.meta testfun +is omitted, the +.code equal +function is used. +The retained items are projected through +.meta mapfun +just like under +.codn remove-if . + +The .code keep-if function is exactly like .codn remove-if , |