从数组中删除第一个匹配元素

36

假设我有一个数组[1,2,3,1,2,3],我想从中删除第一个(比如说)2,使其变为[1,3,1,2,3]。最简单的方法是什么?

3个回答

71
li.delete_at(li.index(n) || li.length)

li[li.length]超出了范围,因此|| li.length处理n不在列表中的情况。

irb(main):001:0> li = [1,2,3,1,2,3]
=> [1, 2, 3, 1, 2, 3]
irb(main):002:0> li.delete_at(li.index(2) || li.length)
=> 2
irb(main):003:0> li.delete_at(li.index(42) || li.length)
=> nil
irb(main):004:0> li
=> [1, 3, 1, 2, 3]

谢谢。我一直在努力寻找优雅地表达这个问题的方法。 - Courtland Caldwell
1
我不理解 || li.length,可以有人解释一下吗? - gates
1
在 Ruby 中,任何值都可以被视为布尔值,只有 falsenil 会被视为假。双竖线语法是一种方便的简写方式。a || b 的意思是“如果 a 不是 nil,则为 a,否则为 b”。 - Eric Haynes
@erich2k8,li.length是另一种说法吗?意思是“不要删除任何东西(因为length(n)总是超出数组范围,并返回'nil')”? - stevec
1
@stevec 是的,完全正确。如果在实际应用中遇到这种情况可能会有点困惑,但这是一种只进行一次遍历的一行代码方式。或者,您可以将索引存储在变量中,然后仅在变量值为非“nil”时执行delete_at。不过,在检查之后,这些变量有点多余。例如,index = arr.index(3) && arr.delete_at(index)之后会保留index变量。 - Eric Haynes
@erich2k8 啊,谢谢你的解释。现在我明白了它的理由。我必须承认,当我第一次阅读它时,我不知道它是做什么的。我真的很喜欢@TNT的建议,将其作为stdlib的一部分。 - stevec

15
如果 || li.length 是为了避免将 nil 传递给 li.delete_at(这会导致 TypeError),那么更易读的版本可能是这样的: li.delete_at(li.index(42)) unless li.index(42).nil?

7
为了避免重复搜索,你可能希望将 li.index(42) 存储在一个变量中。对于大型数组,性能会更好。 - Kelvin

8
也许它应该成为标准库的一部分:
class Array
  def delete_first item
    delete_at(index(item) || length)
  end
end

1
非常同意。当你知道它时,delete_at(index(item) || length)非常容易,但否则并不明显。delete_first非常好用。 - stevec
有没有一个更正式的地方可以提出关于Ruby的建议? - stevec

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