如何检查Ruby数组是否包含多个值之一?

Col*_*len 31 ruby arrays string intersect

我有两个Ruby数组,我需要看看它们是否有任何共同的值.我可以循环遍历一个数组中的每个值,并在另一个数组中包含?(),但我确信有更好的方法.它是什么?(这些数组都包含字符串.)

谢谢.

Mar*_*ers 84

设置相交:

a1 & a2
Run Code Online (Sandbox Code Playgroud)

这是一个例子:

> a1 = [ 'foo', 'bar' ]
> a2 = [ 'bar', 'baz' ]
> a1 & a2
=> ["bar"]
> !(a1 & a2).empty? # Returns true if there are any elements in common
=> true
Run Code Online (Sandbox Code Playgroud)

  • 我会去(a1&a2).是的?而不是!(a1&a2).empty? (6认同)
  • 好吧,OP想"检查",所以布尔结果更合适:!(a1&a2).empty? (3认同)
  • @rilla`any?`在这种情况下有效,但在处理`false`和`nil`值时无效:`[nil,false] .any?#=> false`。 (2认同)
  • @DavidWest 是的,`(a1 & a2).present?`。 (2认同)

Jea*_*ean 7

有什么共同的价值?你可以使用交叉算子:&

[ 1, 1, 3, 5 ] & [ 1, 2, 3 ]   #=> [ 1, 3 ]
Run Code Online (Sandbox Code Playgroud)

如果你正在寻找一个完整的交叉点(有重复),问题就更复杂了,这里已经有一个堆栈溢出:如何返回一个带有重复元素的Ruby数组交集?(骰子系数中的双字母问题)

或者是一个快速片段,它定义"real_intersection"并验证以下测试

class ArrayIntersectionTests < Test::Unit::TestCase    
  def test_real_array_intersection
    assert_equal [2], [2, 2, 2, 3, 7, 13, 49] & [2, 2, 2, 5, 11, 107]
    assert_equal [2, 2, 2], [2, 2, 2, 3, 7, 13, 49].real_intersection([2, 2, 2, 5, 11, 107])
    assert_equal ['a', 'c'], ['a', 'b', 'a', 'c'] & ['a', 'c', 'a', 'd']
    assert_equal ['a', 'a', 'c'], ['a', 'b', 'a', 'c'].real_intersection(['a', 'c', 'a', 'd'])
  end
end
Run Code Online (Sandbox Code Playgroud)


Gal*_*tus 6

使用交集看起来不错,但效率低下。我会用“任何?” 在第一个数组上(以便在第二个数组中找到一个元素时停止迭代)。此外,在第二个数组上使用 Set 将使成员资格检查快速。IE:

a = [:a, :b, :c, :d]
b = Set.new([:c, :d, :e, :f])
c = [:a, :b, :g, :h]

# Do a and b have at least a common value?
a.any? {|item| b.include? item}
# true

# Do c and b have at least a common value?
c.any? {|item| b.include? item}
#false
Run Code Online (Sandbox Code Playgroud)

  • 基准测试表明,这比(更美观的)集合交集方法快 1.5-2 倍,具体取决于简单值与对象属性的比较。正如上面评论中所建议的,使用“any?”而不是“empty?”设置交集,略有不同,但没有改变结果。(严格考虑性能,并且正如预期的那样,因为“有吗?”在第一场比赛中退出。) (3认同)