Пропустить Ruby итератор из внешнего метода - PullRequest
2 голосов
/ 27 февраля 2020

Допустим, у вас есть Ruby итератор, который использует внешний метод в своем блоке:

def external_method(n)
 n.valid? ? n : next  #this "next" expression will result in an error 
end

(1..9).map { |i| external_method(i) } 

Вопрос в том, как вы можете break или next из внешнего метода, используемого внутри итератор.

Ответы [ 4 ]

2 голосов
/ 27 февраля 2020

Можно ли переместить next в блок map? Примерно так:

def external_method(n)
  n.valid? && n
end

(1..9).map { |i| external_method(i) || next }

Кстати, я не уверен, является ли код в вашем вопросе просто примером или реальным кодом. Но мне кажется, что next не имеет никакого смысла, потому что он вызывается последним в блоке, и переход к следующему элементу был бы следующим шагом в map в любом случае.

1 голос
/ 27 февраля 2020

Вопрос на самом деле в том, как вы можете break или next из внешнего метода, используемого внутри итератора.

def external_method(n)
  n.valid? ? n : next
end

Даже если бы это было возможно - мне было бы трудно понять, что делает этот метод. Вы не должны пытаться явно контролировать итерацию извне итерации.

А как насчет получения допустимых значений из вашего внешнего метода обратно в l oop? (не обязательно должно быть n, вы также можете получить измененное значение)

def external_method(n)
  yield n if n.valid?
end

(1..9).map do |i|
  external_method(i) do |n|
    # do something with n
  end
end

Таким образом, блок будет выполняться только если n.valid? и пропущен в противном случае. Возможно, вам придется настроить возвращаемое значение для external_method, чтобы хорошо играть с map. В настоящее время он возвращает только результат блока или nil.

0 голосов
/ 27 февраля 2020

Ruby 2.7 имеет Enumerable # filter_map

(1..10).filter_map { |i| i * 2 if i.even? } #=> [4, 8, 12, 16, 20]

(пример из ссылки do c)

0 голосов
/ 27 февраля 2020

Если external_method нужно много чего сделать, но только если выполнено условие на n, вы всегда можете вернуться, если это условие не будет выполнено, что приведет к разрыву или переходу к следующей итерации, поскольку вызов метода является единственной операцией в блоке:

def external_method(n)
  return unless n.even?

  puts "running block on #{n}"
end

(1..9).map { |i| external_method(i) }

Если блок имеет больше, чем просто вызов метода, и на основе условия в вызове метода вы хотите пропустить все остальные блок, вы можете попробовать ruby throw / catch:

def external_method(n)
  throw :next unless n.even?
end

(1..9).map do |i|
  catch(:next) do
    external_method(i)

    puts "running block on #{i}"
  end
end

Вывод обоих этих фрагментов кода:

running block on 2
running block on 4
running block on 6
running block on 8
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...