Ruby中如何遍历数组并返回首个满足条件的函数返回值
Ruby中获取数组首个触发函数真值的函数返回值(短路求值)
我有一个数组 arr = [x1, x2, x3...],还有一个函数 func —— 核心需求是找到数组中第一个让func(x)返回真值的元素x,直接获取此时func(x)的返回值,同时必须实现短路求值(不用遍历整个数组)。比如数组元素是正则表达式时,要返回首个匹配到的捕获组,而非正则对象本身。
在Python里用next()结合生成器就能轻松实现,但Ruby里刚开始没找到等价写法。试了几种方法都踩了坑:
- 显式循环:能实现但代码太啰嗦,不够优雅;
grep:会遍历整个数组,没法提前终止,不符合短路要求;find:只能返回匹配的元素x(比如正则对象),拿不到func(x)的实际返回值(比如捕获组)。
经过尝试,找到两种可行的解决方案:
方案1:lazy.filter_map组合实现短路求值
Ruby的lazy可以让数组方法延迟执行,配合filter_map能先对每个元素执行func,过滤掉返回假值的结果,然后取第一个符合条件的返回值——关键是lazy会确保处理到第一个有效结果就立刻停止,不会遍历后续元素。
正则捕获组示例
str = "hello 123 world 456" regex_arr = [/foo(\d+)/, /hello (\d+)/, /world (\d+)/] # 只处理到第一个匹配的正则就停止 result = regex_arr.lazy.filter_map { |regex| regex.match(str)&.[](1) }.first puts result # 输出 "123"
解释:filter_map会执行regex.match(str)&.[](1),匹配成功返回捕获组,失败返回nil;lazy保证短路执行,first取出第一个有效结果。
方案2:改造find方法获取结果
find本身返回的是匹配的元素,但我们可以在块内把func(x)的结果存到变量里,一旦块返回真值,find就停止遍历,最后直接用这个变量即可:
正则捕获组示例
str = "hello 123 world 456" regex_arr = [/foo(\d+)/, /hello (\d+)/, /world (\d+)/] result = nil # 块内赋值result,当result为真值时find停止遍历 regex_arr.find { |regex| result = regex.match(str)&.[](1) } puts result # 输出 "123"
这种写法更简洁,不需要依赖lazy,逻辑直观。
通用场景封装
可以把逻辑封装成通用方法,适配任意数组和判断函数:
基于lazy.filter_map的通用方法
def first_func_result(arr, &block) arr.lazy.filter_map { |x| block.call(x) }.first end # 测试:找第一个大于5的元素的平方 arr = [1, 3, 6, 8] result = first_func_result(arr) { |x| x > 5 ? x**2 : nil } puts result # 输出 36
基于find改造的通用方法
def first_func_result(arr, &block) result = nil arr.find { |x| result = block.call(x) } result end # 同样测试 arr = [1, 3, 6, 8] result = first_func_result(arr) { |x| x > 5 ? x**2 : nil } puts result # 输出 36
内容的提问来源于stack exchange,提问作者dawg
相关产品推荐
相关产品推荐

