在递归函数中将条件作为 Proc/Lambda/Block 传递会导致它在 lambda 内部的条件评估为真后退出。为什么?

Passing a condition as a Proc/Lambda/Block in recursive function causes it to exit once the condition inside the lambda has evaluated to true. Why?

所以我想创建一个递归函数,当给定一个数组时,将 return 满足条件的元素数组传递给函数。我尝试过使用 lambda、块和 proc,并且每次当条件计算结果为真时它们退出函数,而不是在满足基本情况时。我想知道这是为什么以及我该如何克服它。

def find_by_condition_recur(arr, count, acc, &block)
  return acc if count == arr.count - 1
  puts count
  puts arr.count
  if block.call(arr[count])
    acc << arr[count]
  else
    find_by_condition_recur(arr, count += 1, acc, &block)
  end
end

编辑:

def find_by_condition_recur(arr, findBy, count, acc)
  return acc if count == arr.count - 1
  puts count
  puts arr.count
  if findBy.call(arr[count])
    acc << arr[count]
    find_by_condition_recur(arr, findBy, count += 1, acc)
  end
end

search_condition = Proc.new { |x| x % 3 == 0 }

这是一些适合您的工作代码:

def find_by_condition_recur(arr, idx=0, acc=[], &findBy)
  return acc if idx == arr.count
  if findBy.call(arr[idx])
    acc << arr[idx]
  end
  find_by_condition_recur(arr, idx + 1, acc, &findBy)
end

find_by_condition_recur([1,2,3]) { |num| num != 2 }
# => [1,3]

有两个主要修复:

  1. 基本情况是 idx == arr.count,而不是 idx == arr.count - 1。如果 idx 越界,您只想在此处 return - arr.count - 1 在范围内 ,所以如果您在这种情况下 return ,您将跳过最后一次迭代。
  2. 你需要将最后的 find_by_condition_recur 调用移到 if findBy.call 块之外,否则递归将在条件失败时立即停止(并且数组的其余部分将不会被处理).

除此之外,我还进行了一些重构:

  1. 参数的默认值。没有理由必须在第一次调用方法时指定 idxacc 参数——我们知道它们将分别是 0[] 所以让我们将这些设置为默认值。
  2. Block 应该始终是最后一个参数,否则您将迫使调用者使用丑陋的 proc/lambda 文字。使用 blocks 更加地道,而且只有当它是最后一个参数时才可以使用 blocks。
  3. 使用 idx 而不是 count 作为变量名,这样更准确。