[Prev][Next][Index][Thread]
Re: Removing a specific item from a collection?
On Tue, 2 May 2000, Dustin Voss wrote:
> I was surprised to find that there doesn't seem to be a way to remove,
> say, element 5 from a stretchy-vector. Explicit key collections (i.e.
> <table>) have the remove-key (or is it remove-element) function, but
> there doesn't seem to be an analogous function for the other collections.
> ...
> This must have come up before; how did you solve it? Can we add such a
> function to the standard?
I don't actually remember ever hitting this (in 2-3 years of Dylan
programming!) but given you want to do it, I think you'd just have to
write your own version.
An easy answer is
--------
define method remove-by-key!
(seq :: <sequence>, key :: <integer>)
=> (new-seq :: <sequence>)
choose-by(curry(\!=, key), range(), seq)
end;
--------
Given that (after some head-scratching) that was so easy, it may not be
worth adding to the standard. Then again, the set of "handy" (as opposed
to "vital") collection functions in the DRM is a little haphazard already.
I (and at least Andy Armstrong :-) think the whole collection hiearchy and
functions could do with a little tweaking for "Dylan the Language 2.0",
but that's a big project (and non-urgent, and not even that *important*,
I think).
A more complex (and *maybe* more efficient) answer is
--------
// Non-exported helper function
// Assumption: new-seq.size >= (seq.size - 1)
define method remove-by-key-into!
(new-seq :: <mutable-sequence>, seq :: <sequence>, key :: <integer>)
=> (new-seq :: <mutable-sequence>)
let original-size :: <integer> = seq.size;
for (i :: <integer> from key,
j :: <integer> from key + 1,
while: j < original-size)
new-seq[i] := seq[j];
end;
new-seq
end;
define method remove-by-key!
(seq :: <stretchy-sequence>, key :: <integer>)
=> (new-seq :: <stretchy-sequence>)
remove-by-key-into!(seq, seq, key);
seq.size := original-size - 1;
seq
end;
define method remove-by-key!
(seq :: <sequence>, key :: <integer>)
=> (new-seq :: <sequence>)
let new-seq = make(seq.type-for-copy, size: seq.size - 1);
remove-by-key-into!(new-seq, seq, key);
new-seq
end;
define method remove-by-key!
(seq :: <list>, key :: <integer>)
=> (new-seq :: <list>)
if (key > 0)
let preceding-pair = seq[key - 1];
let key-pair = preceding-pair.tail;
if (empty?(key-pair))
error("element not found");
else
preceding-pair.tail := key-pair.tail;
seq
end
else
// Can't "remove!" first element of a list as there may be
// bindings pointing directly to the <pair>.
next-method()
end
end;
--------
HTH,
Hugh
Follow-Ups:
References: