RCR 285: Array#delete and Array#delete_at added functionality
Submitted by _ibz (Thu Nov 11 04:11:18 UTC 2004)
Abstract
Array#delete deletes *all* items from _self_ that are equal to the object given as it's argument. I propose an enhancement that would allow caller to select the number of objects that are deleted.
Array#delete_at deletes the element at the specified index, returning that element or _nil_ if the index is out of range. I propose an enhancement that would allow caller to specify several indexes, or ranges of indexes.
Problem
Not a problem, just a nicety which *I* personally think would be an "enhancement", (if the usage of the loaded term can be excused) for a seemingly small amount of code.
Proposal
I believe the code demonstrates that the modifications can be achieved without breaking semantics or backward compatibility. However, I suspect there's a cleaner way to write what I have written.
Analysis
Array#values_at can accept an index or a range. I have tried to model Array#delete_at in a similar way, as delete_at should really allow a range of objects to be deleted - the order of the arguments matters however, since we are modifying the array as we process the arguments.
Array#delete can accept a block, and the block is called when the object is not found. I have tried to model this same behaviour, but when a number of objects specified to be deleted exceeds the number available, then the block will be called once for each time the object is not found.
Implementation
class Array
alias old_delete_at delete_at
def delete_at(*elements)
result = elements.collect do |n|
case
when !n.is_a?(Integer) && !n.is_a?(Range)
raise TypeError, "argument should be Integer or Range"
when n.is_a?(Integer)
old_delete_at(n)
when n.is_a?(Range)
slice!(n)
end
end
return nil if result.empty?
return result[0] if result.size == 1
return result.flatten
end
alias old_delete delete
def delete(element, n = nil, &block)
case
when n == nil
old_delete(element, &block)
when !n.is_a?(Integer)
raise TypeError, "second argument should be Integer or nil!"
when n < 0
result = []
(-n).times do
found = rindex(element)
if found.nil?
block.call(n) if block_given?
else
result << slice!(rindex(element))
end
end
result
when n > 0
result = []
n.times do
found = rindex(element)
if found.nil?
block.call(n) if block_given?
else
result << slice!(found)
end
end
result
end
end
end

I agree this would be a nice feature to have.
For #delete_at try this:
def delete_values_at(*selectors)
idx = []
selectors.each{ |i|
case i
when Range
idx.concat( i.to_a )
else
idx << i.to_i
end
}
idx.uniq!
dvals = values_at(*idx)
idx = (0...size).to_a - idx
self.replace( values_at(*idx) )
return dvals
end
I only recently put this together, so its not tried and true, but my quick testcase is working and I think it handles the need better. Improvements welcome.
I agree though, it might sometimes be helpful if #delete took an optional max number of values to delete.
T.
|
Strongly opposed |
0 |
Opposed |
0 |
Neutral |
0 |
In favor |
3 |
Strongly advocate |
0 |
|
RCRchive copyright © David Alan Black, 2003-2005.
Powered by .
For #delete_at try this:
I only recently put this together, so its not tried and true, but my quick testcase is working and I think it handles the need better. Improvements welcome.
I agree though, it might sometimes be helpful if #delete took an optional max number of values to delete.
T.