如何按值从数组中删除一个元素
Posted
技术标签:
【中文标题】如何按值从数组中删除一个元素【英文标题】:How can I delete one element from an array by value 【发布时间】:2012-04-19 13:14:26 【问题描述】:我在 Ruby 中有一个元素数组
[2,4,6,3,8]
例如,我需要删除值为 3
的元素
我该怎么做?
【问题讨论】:
我想知道为什么delete
array.delete(3)
在 ruby on rails 控制器中不起作用
可能是由于active record
方法delete
问题的标题和正文是矛盾的。正如标题所暗示的那样,您的目标是删除一个具有给定值的元素吗?或者,正如正文所暗示的那样,您的目标是删除具有给定值的所有元素?这两个目标是互斥的;每个人都有不同的解决方案。
【参考方案1】:
我喜欢其他答案中提到的-=[4]
方式删除值为4的元素。
但是有这种方式:
[2,4,6,3,8,6].delete_if |i| i == 6
=> [2, 4, 3, 8]
在“Basic Array Operations”中某处提到了map
函数。
【讨论】:
但是你不能只使用.delete(6)
@Zac 当然,但这个答案已经被提及(就像非常简洁的 -=
方式 a-=[4]
即 a=a-[4]
. [3,4]-[4]
,我说我喜欢),但我想提一下另一种可能的方式。
这个方法还有一个好处就是返回数组而不是被删除的元素。【参考方案2】:
我想我已经明白了:
a = [3, 2, 4, 6, 3, 8]
a.delete(3)
#=> 3
a
#=> [2, 4, 6, 8]
【讨论】:
我个人喜欢[1, 2, 3, 4, 5] - [3]
,这导致=> [1, 2, 4, 5]
来自irb
。
如果有多个 3 条目,而我们只想删除其中一个呢? (这是相关的,所以在这里问这个可能是最好的)
请注意,.delete() 将返回删除的值,而不是删除值的修改后的数组。
另一个需要考虑的后果是delete
改变了底层数组,而-
创建了一个没有删除值的新数组(返回给您)。根据您的用例,任何一种方法都可能有意义。
@user3721428,delete(3) 不引用位置 3 的元素,而是删除与整数 3 匹配的任何元素。它将删除所有出现的 3,并且与数组索引无关或位置。【参考方案3】:
在 ruby 中编译所有不同的删除选项
delete - 按值删除匹配的元素。如果多个值匹配,它将全部删除。如果你不关心出现的次数或者确定单次出现,就用这个方法吧。
a = [2, 6, 3, 5, 3, 7]
a.delete(3) # returns 3
puts a # return [2, 6, 5, 7]
delete_at - 删除给定索引处的元素。如果您知道索引,请使用此方法。
# continuing from the above example
a.delete_at(2) # returns 5
puts a # returns [2, 6, 7]
delete_if - 删除所有块为真的元素。这将修改数组。调用块时,数组会立即更改。
b = [1, 2, 5, 4, 9, 10, 11]
b.delete_if |n| n >= 10. # returns [1, 2, 5, 4, 9]
reject - 这将返回新数组,其中包含给定块为假的元素。以此保持顺序。
c = [1, 2, 5, 4, 9, 10, 11]
c.reject |n| n >= 10. # returns [1, 2, 5, 4, 9]
reject! - 与 delete_if 相同。调用块时,数组可能不会立即更改。
如果你想从数组中删除多个值,最好的选择如下。
a = [2, 3, 7, 4, 6, 21, 13]
b = [7, 21]
a = a - b # a - [2, 3, 4, 6, 13]
【讨论】:
【参考方案4】:如果你还想让这个删除操作可以链接,那么你可以删除一些项目并继续对结果数组进行链接操作,使用tap
:
[2, 4, 6, 3, 8].tap |ary| ary.delete(3) .count #=> 4
【讨论】:
【参考方案5】:第一次出现的无损删除:
a = [2, 4, 6, 3, 8]
n = a.index 3
a.take(n)+a.drop(n+1)
【讨论】:
【参考方案6】:我不确定是否有人说过这一点,但 Array.delete() 和 -= value 将删除数组中传递给它的值的每个实例。为了删除特定元素的第一个实例,您可以执行类似的操作
arr = [1,3,2,44,5]
arr.delete_at(arr.index(44))
#=> [1,3,2,5]
可能有更简单的方法。我并不是说这是最佳做法,但这是应该得到认可的。
【讨论】:
我正在寻找一种方法来做到这一点,并且只删除重复元素的一个实例,这很好用! 我认为这个答案是错误的,仅仅是因为 arr.index() 可以去nil
【参考方案7】:
假设您要在数组中的多个位置按值删除 3, 我认为完成这项任务的 ruby 方法是使用 delete_if 方法:
[2,4,6,3,8,3].delete_if |x| x == 3
你也可以在'array of arrays'场景中使用delete_if删除元素。
希望这能解决您的问题
【讨论】:
【参考方案8】:因此,当您多次出现 3 并且只想删除第一次出现的 3 时,您可以简单地执行以下操作。
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.
【讨论】:
【参考方案9】:以下是一些基准:
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
再次使用包含大量重复项的更大数组:
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
甚至更大,重复次数更多:
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
【讨论】:
那么,什么是最好的? :)【参考方案10】:您也可以对其进行修补。我一直不明白为什么 Ruby 对 Hash
有一个 except
方法,但对 Array
没有:
class Array
def except value
value = value.kind_of(Array) ? value : [value]
self - value
end
end
现在你可以这样做了:
[1,3,7,"436",354,nil].except(354) #=> [1,3,7,"436",nil]
或者:
[1,3,7,"436",354,nil].except([354, 1]) #=> [3,7,"436",nil]
【讨论】:
您不需要value.kind_of(Array)
测试。只需使用self - Array(value)
。【参考方案11】:
你可以简单地运行:
[2,4,6,3,8].delete(3)
【讨论】:
【参考方案12】:我改进了 Niels 的解决方案
class Array
def except(*values)
self - values
end
end
现在你可以使用
[1, 2, 3, 4].except(3, 4) # return [1, 2]
[1, 2, 3, 4].except(4) # return [1, 2, 3]
【讨论】:
您的解决方案无法在irb
控制台上运行 2.2.1 :007 > [1, 2, 3, 4].except(3, 4) NoMethodError: undefined method except for [1, 2, 3, 4]:Array from (irb):7 from /usr/share/rvm/rubies/ruby-2.2.1/bin/irb:11:in <main>
要在IRB中声明,需要将方法添加到Array class Array; def except(*values); self - values; end; end
。【参考方案13】:
借用 cmets 中的 Travis,这是一个更好的答案:
我个人喜欢
[1, 2, 7, 4, 5] - [7]
,这导致=> [1, 2, 4, 5]
来自irb
我修改了他的答案,发现 3 是他的示例数组中的第三个元素。对于那些没有意识到 3 在数组中的位置 2 的人来说,这可能会导致一些混乱。
【讨论】:
正如 srt32 在答案中指出的那样,使用.delete
和 -
之间有一个重要的区别。 .delete
将返回从数组中删除的值,如果有的话; -
不会。所以[ 1, 2, 3 ] - [ 2 ]
将返回[ 1, 3 ]
,而[ 1, 2, 3 ].delete( 2 )
将返回2
。
array - subArray
不适用于 Array of Arrays,但 array.delete(subArray)
可以。
[1,2,3] - [2]
和[1,2,3].delete(2)
之间非常重要的区别在于delete
方法修改了原始数组,而[1,2,3] - [3]
创建了一个新数组.
重新子数组(@Sachin 上面的评论)“当然可以”,你只需要正确的符号:[1,2,[2],2,3,4] - [2]
给你[1, [2], 3, 4]
,但[1,2,[2],2,3,4] - [[2]]
给你[1, 2, 2, 3, 4]
。 :-)【参考方案14】:
.delete_at(3)
3
是这个位置。
【讨论】:
【参考方案15】:另一种选择:
a = [2,4,6,3,8]
a -= [3]
导致
=> [2, 4, 6, 8]
【讨论】:
以上是关于如何按值从数组中删除一个元素的主要内容,如果未能解决你的问题,请参考以下文章