根据部分已知的值检查数组内容的干净的 Rubyist 方法是什么?

jbk*_*jbk 3 ruby regex include pattern-matching

我有一个 3d 数组,我需要根据部分已知的值检查它的第二个“维度”。数组组成图解如下:

a = [[[1,1], nil]], [[2,3], [4,8]], [[6,1],[9,9]], [[5,7], nil]]]
Run Code Online (Sandbox Code Playgroud)

我需要检查这个数组是否存在包含两个值的数组,第一个值我会知道其确切内容,但第二个值我所知道的是它要么是一个nil未知的 2 元素数组个位数的值。在伪代码中我想做的是;a.include?([[1,1],*unknown*])

也许正则表达式匹配器是这里的出路(?)。也许类似;

a.include?([[1,1],/\[\d,\d\]||(nil)])(我想说的是;[任何单个 0-9 数字,任何单个 0-9 数字] 或“nil”)

任何帮助表示赞赏。

Car*_*and 7

据我了解,问题如下:“给定一个包含双元素数组的数组,确定其至少一个元素是否使其第一个元素等于给定的双元素数组,并且其第二个元素等于 nil 或数组由两个单位数自然数组成”。

您可以使用以下方法来确定给定数组是否具有该属性。

def is_it_there?(arr, first_known)
  arr.any? do |first,second|
    first == first_known &&
    (second.nil? ||
      (second.is_a?(Array) &&
       second.size == 2 && 
       second.all?(Integer) &&
       second.all?(0..9)
      )
    )
  end
end
Run Code Online (Sandbox Code Playgroud)
arr = [[[1,1], nil], [[2,3], [4,8]], [[6,1], 0..9], [[5,7], nil],
       [[3,8], 2], [[7,6], [1,2,3]], [[3,1], [1,12]],
       [[2,2], [-1,2]], [[0,1], [3,4.5]]]         
Run Code Online (Sandbox Code Playgroud)
is_it_there?(arr, [2,3]) #=> true
is_it_there?(arr, [1,1]) #=> true
is_it_there?(arr, [5,7]) #=> true
Run Code Online (Sandbox Code Playgroud)
is_it_there?(arr, [1,6]) #=> false
is_it_there?(arr, [3,8]) #=> false
is_it_there?(arr, [7,6]) #=> false
is_it_there?(arr, [3,1]) #=> false
is_it_there?(arr, [2,2]) #=> false
is_it_there?(arr, [6,1]) #=> false
is_it_there?(arr, [0,1]) #=> false
Run Code Online (Sandbox Code Playgroud)

看到Enumerable#any的版本了吗?以模式作为参数。(其他Enumerable采用模式作为参数的方法有Enumerable#all?Enumerable#one?Enumerable#none?)。

  • `second.all?(0..9)` 也应该有效。 (3认同)

eng*_*nky 5

虽然“查找模式”仍处于实验阶段,但您的用例非常适合模式匹配

例如:

arr = [[[1,1], nil], [[2,3], [4,8]], [[6,1], [9,9]],
       [[2,3], [3,7]], [[5,7], nil],[[7,9],[42,1]]]

def matches_known_pattern?(arr,known)  
  arr in [*,[^known,nil|[0..9,0..9]],*]
end 

matches_known_pattern?(arr,[1,1]) #=> true
matches_known_pattern?(arr,[2,3]) #=> true 
matches_known_pattern?(arr,[7,8]) #=> false
matches_known_pattern?(arr,[7,9]) #=> false because 42 does not match 0..9
matches_known_pattern?(arr,[1,'a']) #=> false
Run Code Online (Sandbox Code Playgroud)

该模式相当不言自明,但它可以分解为a[0] == knownand a[1] == nilor是 0 到 9 之间的任何 2 个整数数字(包括、等)a[1]的数组。如果您想允许任何整数,您可以替换为。如果您根本不关心是什么,那么您可以使用(这与您建议的模式相当接近)IntegerFloat[0..9,0..9][Integer,Integer]a[1]*[[1,1],*unknown*]

两侧是实验性的[*,...,*]“查找模式”部分。本质上它只是意味着在任何地方找到这个模式(第一场比赛获胜)。arr

另一个注意事项是,^known因为模式匹配允许在没有插入符 ( ^) 的情况下进行变量绑定,因此变量将被分配模式中known第一个元素 ( ) 的值。a[0][0]“固定^”局部变量known或如文档中所述“对于这种情况,可以使用 pin 运算符^来告诉 Ruby '仅使用该值作为模式的一部分'”

感谢@steenslag指出 Find Pattern 不再是实验性的

更新 为了涵盖这种情况,@CarySwoveland指出([[8,8],[1,4.6]])这需要更改为:

case arr 
in [*,[^known,[Integer=>a,Integer=>b]],*]
    (0..9).cover?(a) && (0..9).cover?(b)
in [*,[^known,nil],*]
    true
else 
    false 
end 
Run Code Online (Sandbox Code Playgroud)

其中Integernil检查被分隔开,因为变量绑定不可用于替代表达式(用 分隔|