[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: