Ruby中Proc分区方法的if条件判断异常问题排查
代码核心问题解析
- 二维数组判断逻辑错误:你用
arr != arr.flatten判断是否为二维数组完全不成立——一维数组的扁平化结果和自身内容一致,arr == arr.flatten会返回true,所以第一次调用直接进入else块,返回空的passed + failed,这就是你得到空数组的原因。正确的判断应该是检查传入的是否是包含两个子数组的结构:arr.size == 2 && arr.all? { |sub| sub.is_a?(Array) }。 - 递归未返回结果:你在
each_with_index里调用了递归方法,但没有把递归结果返回,上层方法根本拿不到后续处理的结果,最终还是走else返回空数组。 pop用法混乱:arr[1].pop(arr.size - i +1)的计算逻辑错误,传入的二维数组arr.size是2,表达式结果为3 - i,当i=0时会直接把剩余元素数组清空,导致循环只执行一次;而且pop会修改原数组,引发后续逻辑混乱。- 作用域维护失败:每个递归层级的
passed和failed都是局部变量,下层递归的修改不会影响上层,你想通过递归维护作用域的思路完全没实现。
修正后的递归实现
如果坚持用递归思路,推荐采用“逐元素处理+递归传递状态”的方式,避免修改原数组:
def proctition(arr, &prc) # 基准情况:数组为空时返回分区结果 return [[], []] if arr.empty? first_ele = arr.first rest_elements = arr[1..-1] # 递归处理剩余元素,拿到后续的分区结果 passed, failed = proctition(rest_elements, &prc) # 根据Proc判断当前元素的归属 if prc.call(first_ele) [passed.unshift(first_ele), failed] else [passed, failed.unshift(first_ele)] end end # 测试示例 arr = [1,2,3,4,5] p proctition(arr) { |num| num.even? } # => [[2,4], [1,3,5]]
如果一定要用你最初设想的“传入二维结构维护状态”的递归方式,也可以修正为:
def proctition(arr, &prc) # 判断是否处于递归状态(传入的是[已通过元素, 剩余元素]) if arr.size == 2 && arr.all? { |sub| sub.is_a?(Array) } passed, remaining = arr # 基准情况:剩余元素为空,返回最终分区结果 return [passed, []] if remaining.empty? current_ele = remaining.first if prc.call(current_ele) # 符合条件就加入已通过数组,递归处理剩余元素 proctition([passed + [current_ele], remaining[1..-1]], &prc) else # 不符合则先递归处理剩余,再把当前元素加入失败数组 passed_part, failed_part = proctition([passed, remaining[1..-1]], &prc) [passed_part, failed_part + [current_ele]] end else # 初始调用,传入初始状态开始递归 proctition([[], arr], &prc) end end # 测试示例 arr = [1,2,3,4,5] p proctition(arr) { |num| num.even? } # => [[2,4], [1,3,5]]
额外说明
你提到“没有类似pop()的方法可以选择性移除数组元素并返回被移除元素”,其实Ruby里有slice!(index)可以移除指定位置的元素并返回它,或者shift移除第一个元素、pop移除最后一个元素。但递归中建议用切片(比如arr[1..-1])生成新数组,避免修改原数组引发的副作用。
内容的提问来源于stack exchange,提问作者user22771170
相关产品推荐
相关产品推荐

