什么是一个干净的Rubyist方法来检查数组的内容是否部分已知?

8i9zcol2  于 2023-05-06  发布在  Ruby
关注(0)|答案(2)|浏览(93)

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

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

我需要检查这个数组是否存在包含两个值的数组,第一个我知道确切的内容,但第二个我只知道它要么是nil,要么是一个包含未知个位数值的2元素数组。在伪代码中我想做的是a.include?([[1,1],*unknown*])
也许正则表达式匹配器是这里要走的路(?)。也许类似于;
a.include?([[1,1],/\[\d,\d\]||(nil)])(我想说的是;[任何单个0-9数字,任何单个0-9数字]或“nil”)
任何帮助感激不尽。

jum4pzuy

jum4pzuy1#

根据我的理解,问题如下:“给定一个包含两个元素的数组,确定是否至少有一个元素是这样的,它的第一个元素等于给定的两个元素数组,第二个元素等于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
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]]]
is_it_there?(arr, [2,3]) #=> true
is_it_there?(arr, [1,1]) #=> true
is_it_there?(arr, [5,7]) #=> true
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

查看Enumerable#any的版本?以一个模式作为参数。(其他接受模式作为参数的Enumerable方法是Enumerable#all?,Enumerable#one?可枚举的#none?).

ppcbkaq5

ppcbkaq52#

虽然“查找模式”仍处于试验阶段,但您的用例非常适合Pattern matching
例如:

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

该模式是相当自我解释的,但它分解为a[0] == knowna[1] == nila[1]是0和9之间的任何2个整数数值(包括IntegerFloat等)的数组。如果你想允许任何整数,你可以用[Integer,Integer]替换[0..9,0..9]。如果您根本不关心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

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

相关问题