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

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] 

【讨论】:

以上是关于如何按值从数组中删除一个元素的主要内容,如果未能解决你的问题,请参考以下文章

如何通过名称值从数组中删除字典元素[重复]

使用支持 IE8 的 JavaScript 中的值从数组中删除一个元素 [重复]

使用两个匹配的子值从关联数组中删除元素

使用 jQuery 按值删除 JSON 数组中的元素

在mysql json中按值删除数组元素

根据值从多维数组中删除元素