I have an array of elements in Ruby
[2,4,6,3,8]
I need to remove elements with value 3
for example
How do I do that?
Borrowing from Travis in the comments, this is a better answer:
I personally like
[1, 2, 7, 4, 5] - [7]
which results in=> [1, 2, 4, 5]
fromirb
I modified his answer seeing that 3 was the third element in his example array. This could lead to some confusion for those who don't realize that 3 is in position 2 in the array.
I'm not sure if anyone has stated this, but Array.delete() and -= value will delete every instance of the value passed to it within the Array. In order to delete the first instance of the particular element you could do something like
arr = [1,3,2,44,5]
arr.delete_at(arr.index(44))
#=> [1,3,2,5]
There could be a simpler way. I'm not saying this is best practice, but it is something that should be recognized.
I like the -=[4]
way mentioned in other answers to delete the elements whose value is 4.
But there is this way:
[2,4,6,3,8,6].delete_if { |i| i == 6 }
=> [2, 4, 3, 8]
mentioned somewhere in "Basic Array Operations", after it mentions the map
function.
Here are some benchmarks:
require 'fruity'
class Array
def rodrigo_except(*values)
self - values
end
def niels_except value
value = value.kind_of?(Array) ? value : [value]
self - value
end
end
ARY = [2,4,6,3,8]
compare do
soziev { a = ARY.dup; a.delete(3); a }
steve { a = ARY.dup; a -= [3]; a }
barlop { a = ARY.dup; a.delete_if{ |i| i == 3 }; a }
rodrigo { a = ARY.dup; a.rodrigo_except(3); }
niels { a = ARY.dup; a.niels_except(3); }
end
# >> Running each test 4096 times. Test will take about 2 seconds.
# >> soziev is similar to barlop
# >> barlop is faster than steve by 2x ± 1.0
# >> steve is faster than rodrigo by 4x ± 1.0
# >> rodrigo is similar to niels
And again with a bigger array containing lots of duplicates:
class Array
def rodrigo_except(*values)
self - values
end
def niels_except value
value = value.kind_of?(Array) ? value : [value]
self - value
end
end
ARY = [2,4,6,3,8] * 1000
compare do
soziev { a = ARY.dup; a.delete(3); a }
steve { a = ARY.dup; a -= [3]; a }
barlop { a = ARY.dup; a.delete_if{ |i| i == 3 }; a }
rodrigo { a = ARY.dup; a.rodrigo_except(3); }
niels { a = ARY.dup; a.niels_except(3); }
end
# >> Running each test 16 times. Test will take about 1 second.
# >> steve is faster than soziev by 30.000000000000004% ± 10.0%
# >> soziev is faster than barlop by 50.0% ± 10.0%
# >> barlop is faster than rodrigo by 3x ± 0.1
# >> rodrigo is similar to niels
And even bigger with more duplicates:
class Array
def rodrigo_except(*values)
self - values
end
def niels_except value
value = value.kind_of?(Array) ? value : [value]
self - value
end
end
ARY = [2,4,6,3,8] * 100_000
compare do
soziev { a = ARY.dup; a.delete(3); a }
steve { a = ARY.dup; a -= [3]; a }
barlop { a = ARY.dup; a.delete_if{ |i| i == 3 }; a }
rodrigo { a = ARY.dup; a.rodrigo_except(3); }
niels { a = ARY.dup; a.niels_except(3); }
end
# >> Running each test once. Test will take about 6 seconds.
# >> steve is similar to soziev
# >> soziev is faster than barlop by 2x ± 0.1
# >> barlop is faster than niels by 3x ± 1.0
# >> niels is similar to rodrigo
Compiling all the different options for delete in ruby
delete - Deletes matching elements by value. If more than one value matches it will remove all. If you don't care about the number of occurrence or sure about single occurrence, use this method.
a = [2, 6, 3, 5, 3, 7]
a.delete(3) # returns 3
puts a # return [2, 6, 5, 7]
delete_at - Deletes element at given index. If you know the index use this method.
# continuing from the above example
a.delete_at(2) # returns 5
puts a # returns [2, 6, 7]
delete_if - Deletes every element for which block is true. This will modify the array. Array changes instantly as the block is called.
b = [1, 2, 5, 4, 9, 10, 11]
b.delete_if {|n| n >= 10}. # returns [1, 2, 5, 4, 9]
reject - This will return new array with the elements for which the given block is false. The ordering is maintained with this.
c = [1, 2, 5, 4, 9, 10, 11]
c.reject {|n| n >= 10}. # returns [1, 2, 5, 4, 9]
reject! - same as delete_if. Array may not change instantly as the block is called.
If you want to delete multiple values from array, the best option is as bellow.
a = [2, 3, 7, 4, 6, 21, 13]
b = [7, 21]
a = a - b # a - [2, 3, 4, 6, 13]
You can also monkey patch it. I never understood why Ruby has an except
method for Hash
but not for Array
:
class Array
def except value
value = value.kind_of(Array) ? value : [value]
self - value
end
end
Now you can do:
[1,3,7,"436",354,nil].except(354) #=> [1,3,7,"436",nil]
Or:
[1,3,7,"436",354,nil].except([354, 1]) #=> [3,7,"436",nil]
So when you have multiple occurrences of 3 and you want only to delete the first occurrence of 3, you can simply do some thing as below.
arr = [2, 4, 6, 3, 8, 10, 3, 12]
arr.delete_at arr.index 3
#This will modify arr as [2, 4, 6, 8, 10, 3, 12] where first occurrence of 3 is deleted. Returns the element deleted. In this case => 3.
delete
array.delete(3)
not works within ruby on rails controller – Maniactive record
methoddelete
– Mani