Say I have the array [1,2,3,1,2,3] and I want to delete the first instance of (say) 2 from the array giving [1,3,1,2,3]. What's the easiest way?
3 Answers
li.delete_at(li.index(n) || li.length)
li[li.length] is out of range, so the || li.length handles the case where n isn't in the list.
irb(main):001:0> li = [1,2,3,1,2,3]
=> [1, 2, 3, 1, 2, 3]
irb(main):002:0> li.delete_at(li.index(2) || li.length)
=> 2
irb(main):003:0> li.delete_at(li.index(42) || li.length)
=> nil
irb(main):004:0> li
=> [1, 3, 1, 2, 3]
6 Comments
Courtland Caldwell
Thank you. I've been beating my head trying to express this elegantly.
gates
I don't understand the
|| li.length can anyone please explainEric Haynes
Any value in ruby can be treated as a boolean value, with only
false and nil evaluating to false. The double pipe syntax is a convenient shorthand. a || b means "a, unless it's nil, then b".stevec
@erich2k8 so is
li.length just another way of saying "don't delete anything (since length(n) is always beyond the array, and return 'nil'?"Eric Haynes
@stevec Yes, exactly. This might be a bit confusing if encountered in the wild, but it's a way to make it a 1-liner that only does one traversal. Alternatively, you could store the index in a variable, then do the
delete_at only if the variable value is non nil. Such variables are kind of just clutter after the check though. E.g. index = arr.index(3) && arr.delete_at(index) leaves that index variable around afterwards. |
If || li.length is to avoid sending nil to li.delete_at (which would result in a TypeError), then a more readable version might look like this
li.delete_at li.index(42) unless li.index(42).nil?
1 Comment
Kelvin
You probably want to store
li.index(42) in a variable, to prevent doing the search twice. The performance will be much better for large arrays.Maybe it should become part of stdlib:
class Array
def delete_first item
delete_at(index(item) || length)
end
end