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

我在Ruby中有一个元素数组

[2,4,6,3,8]

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

我怎么做呢?

453767 次浏览

我想我明白了:

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

借用评论中的特拉维斯,这是一个更好的答案:

我个人喜欢[1, 2, 7, 4, 5] - [7],它从irb得到=> [1, 2, 4, 5]

我修改了他的答案,因为3是他示例数组中的第三个元素。对于那些没有意识到3在数组中的位置2的人来说,这可能会导致一些困惑。

另一个选择:

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


a -= [3]

结果是

=> [2, 4, 6, 8]

你可以简单地运行:

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

A .delete_at(3) 3在这里是位置。

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

但有这样一种方法:

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

在提到map函数之后,在“;阵列基本操作"中某处提到。

你也可以猴子修补它。我一直不明白为什么Ruby对Hashexcept方法,而对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]

我改进了尼尔斯的解决方案

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]

以下是一些基准:

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

因此,当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.

假设你想在一个数组的多个地方按值删除3, 我认为ruby执行此任务的方法是使用delete_if方法:

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

你也可以使用delete_if来删除'array of arrays'场景中的元素。

希望这能解决你的疑问

我不确定是否有人已经声明了这一点,但Array.delete()和-= 价值将删除数组中传递给它的每个值的实例。为了删除特定元素的第一个实例,您可以执行如下操作

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


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

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

首次发生的无损清除:

a = [2, 4, 6, 3, 8]
n = a.index 3
a.take(n)+a.drop(n+1)

如果你还想让这个删除操作具有可链性,这样你就可以删除一些项并继续对结果数组进行链接操作,请使用tap:

[2, 4, 6, 3, 8].tap { |ary| ary.delete(3) }.count #=> 4

在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 -删除block为true的每个元素。这将修改数组。数组在调用块时立即改变。

b = [1, 2, 5, 4, 9, 10, 11]
b.delete_if {|n| n >= 10}.  # returns [1, 2, 5, 4, 9]

拒绝 -该函数将返回包含给定块为false的元素的新数组。顺序是用这个来维持的。

c = [1, 2, 5, 4, 9, 10, 11]
c.reject {|n| n >= 10}.  # returns [1, 2, 5, 4, 9]

拒绝! -与delete_if相同。数组在调用块时可能不会立即改变。

如果你想从数组中删除多个值,最好的选择如下所示。

a = [2, 3, 7, 4, 6, 21, 13]
b = [7, 21]
a = a - b    # a - [2, 3, 4, 6, 13]