如何通过值从数组中删除一个元素

426

我有一个 Ruby 数组

[2,4,6,3,8]

我需要删除值为3的元素,例如

我该怎么做?


我想知道为什么deletearray.delete(3)在Ruby on Rails控制器中无法正常工作。 - Mani
2
可能是由于Active Record方法delete - Mani
2
问题的标题和正文是矛盾的。你的目标是删除一个具有给定值的元素,就像标题所暗示的那样吗?还是你的目标是删除所有具有给定值的元素,就像正文所暗示的那样?这两个目标是互斥的;每个目标都有不同的解决方案。 - Ben Amos
15个回答

601

我想我已经弄清楚了:

a = [3, 2, 4, 6, 3, 8]
a.delete(3)
#=> 3
a
#=> [2, 4, 6, 8]

221
我个人喜欢 [1, 2, 3, 4, 5] - [3] 这个操作,它的结果是 => [1, 2, 4, 5],在 irb 中执行。 - Travis
30
如果有多个数字3的条目,我们想要删除其中一个,该怎么办?(这是相关的问题,所以在这里提问可能会更好)。 - Navneet
128
提醒一下,.delete() 方法返回已删除的值,而不是已移除该值后的修改后的数组。 - Joshua Pinter
28
需要考虑的另一个后果是,delete 会改变基础数组(即在原数组上进行修改),而 - 则创建一个新数组(并将其返回给您),删除原数组中的值。根据您的用例,两种方法都可能有意义。 - srt32
3
@user3721428,delete(3)不是指删除在位置3的元素,而是删除与整数3匹配的任何元素。它将删除所有出现的3,并与数组的索引或位置无关。 - bkunzi01
显示剩余4条评论

268

借鉴评论中的Travis,这是更好的答案:

我个人喜欢 [1, 2, 7, 4, 5] - [7],其结果为 => [1, 2, 4, 5] (在irb中)

我修改了他的答案,因为在他的示例数组中,3是第三个元素。这可能会导致一些人混淆,不知道3在数组中的位置是第二个。


22
正如srt32在回答中指出的那样,使用.delete-之间有一个重要区别。如果有值被移除,.delete会返回该值;而-不会返回任何值。因此,[ 1, 2, 3 ] - [ 2 ]将返回 [ 1, 3 ],而[ 1, 2, 3 ].delete( 2 )将返回 2 - Argus9
5
对于“数组中的数组”,使用“array-subArray”将不起作用,但是可以使用“array.delete(subArray)”。 - Sachin
22
[1,2,3] - [2][1,2,3].delete(2) 的一个非常重要的区别是 delete 方法修改原始数组,而 [1,2,3] - [3] 则创建了一个新数组 - Timothy Kovalev
1
重组子数组(@Sachin评论)“当然可以”,你只需要正确地使用符号:[1,2,[2],2,3,4] - [2] 会给出 [1, [2], 3, 4],但是 [1,2,[2],2,3,4] - [[2]] 则会给出 [1, 2, 2, 3, 4]。 :-) - Tom Hundt

76

另一个选择:

a = [2,4,6,3,8]

a -= [3]

导致

=> [2, 4, 6, 8] 

74

我不确定是否有人提到过,但是Array.delete()-= value将删除数组中传递给它的每个值的实例。为了删除特定元素的第一个实例,您可以执行以下操作:

arr = [1,3,2,44,5]
arr.delete_at(arr.index(44))

#=> [1,3,2,5]

可能有更简单的方法。我不是说这是最佳实践,但应该被认可。


1
我一直在寻找一种方法来做到这一点,并且只删除元素的一个实例以防重复,这个方法非常好用! - xeroshogun
我认为这个答案是错误的,因为arr.index()可能返回nil - windmaomao

44
假设您想要在数组的多个位置按值删除3,我认为用Ruby完成这个任务的方法是使用delete_if方法:
[2,4,6,3,8,3].delete_if {|x| x == 3 } 

你也可以使用delete_if在“数组中的数组”中删除元素。


32

我喜欢其他回答中提到的通过-=[4]的方式删除值为4的元素。

但还有这种方式:

[2,4,6,3,8,6].delete_if { |i| i == 6 }
=> [2, 4, 3, 8]

在“数组的基本操作”中提到,在它提到了map函数之后。


但是你不能只使用.delete(6)吗? - Zac
@Zac 当然,但是那个答案已经被提到过了(就像非常简洁的-=方式a-=[4]a=a-[4]。我喜欢的[3,4]-[4]也被提到了),但我想提及另一种可能的方法。 - barlop
该方法还具有返回数组而不是已删除元素的优点。 - F.Webber

23

您可以简单地运行:

[2,4,6,3,8].delete(3)

21

这里的.delete_at(3)是指删除索引为3的元素。


17

这里是一些基准测试结果:

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
那么,什么是最好的? :) - Kirby
1
@Kirby,这很简单,只需查看两个测试代码中的注释即可。Steve的解决方案似乎是最有效的,而barlop和niels的解决方案则是效率最低的。 - marzapower

8
我改进了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> - hgsongra
1
要在IRB中声明,您需要将该方法添加到Array类中 class Array; def except(*values); self - values; end; end - Mark Swardstrom

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接