Передача условия в виде Proc / Lambda / Block в рекурсивной функции приводит к его выходу, когда условие внутри лямбда-функции оценивается как true. Почему? - PullRequest
0 голосов
/ 15 января 2020

Итак, я хочу создать рекурсивную функцию, которая при получении массива будет возвращать массив элементов, соответствующих условию, переданному в функцию. Я попытался использовать лямбда-выражения, блоки и процедуры, и каждый раз, когда они выходят из функции, как только это условие оценивается как истинное, а не при соблюдении базового варианта. Я хочу знать, почему это так и как я могу это преодолеть.

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 }

1 Ответ

1 голос
/ 15 января 2020

Вот некоторый рабочий код для вас:

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 находится за пределами - arr.count - 1 равен в пределах , поэтому, если вы вернетесь в этом случае, вы пропустите последнюю итерацию.
  2. Вам необходимо переместить последний вызов find_by_condition_recur за пределы блока if findBy.call, в противном случае рекурсия остановится, как только произойдет сбой условия (а остальная часть массива не будет обработана).

Кроме этого, я сделал несколько рефакторингов:

  1. Значения по умолчанию для аргументов. Нет необходимости указывать idx или acc аргументы при первом вызове метода - мы знаем, что они будут 0 и [] соответственно, поэтому давайте просто установим их в качестве значений по умолчанию.
  2. Блок всегда должен быть последним аргументом, в противном случае вы заставляете вызывающую сторону использовать уродливый литерал proc / lambda. Гораздо более идиоматично c использовать блоки, и вы можете использовать блоки только тогда, когда это последний аргумент.
  3. Использование idx вместо count в качестве имени переменной, это просто более точно.
...