Каковы различия, используя "любой?" а "собрать" в Ruby? - PullRequest
0 голосов
/ 17 января 2020

У меня есть этот метод здесь:

def present? char_list
  !char_list.collect { |char| utf8?( char ) && char.blank? }.all?
end

Я хотел бы заменить его на это:

def present? char_list
  char_list.any? { |char| utf8?( char ) && !char.blank? }
end

У меня возникают проблемы с пониманием, действительно ли они логически эквивалентно. Я чувствую, что эти методы одинаковы, но я не могу доказать это. Цель использования any? состоит в том, что он остановит обработку, как только найдет элемент, соответствующий условиям.

1 Ответ

4 голосов
/ 18 января 2020

Нет, они не эквивалентны, но вы близко. Чтобы показать вам почему, я возьму в качестве аксиоматики c эти два правила:

  1. Эти два выражения эквивалентны:

    a.collect {|x| pred(x) }.all?
    a.all? {|x| pred(x) }
    
  2. Эти два выражения эквивалентны:

    a.all? {|x| pred(x) }
    !a.any? {|x| !pred(x) }
    

Давайте применим это к вашему коду. Во-первых, вытащите логи c из своего блока, чтобы было немного легче рассуждать о:

def pred(char)
  utf8?(char) && char.blank?
end

!char_list.collect {|char| pred(char) }.all?

Теперь, применяя аксиому (1), мы можем изменить выражение .collect {...}.all? на .all? {...} , что дает нам:

!char_list.all? {|char| pred(char) }

Применяя аксиому (2), мы можем превратить выражение all? в отрицательное any?:

!!char_list.any? {|char| !pred(char) }

Конечно, двойное отрицание (!!) - это то же самое, что отсутствие отрицания, поэтому мы имеем:

char_list.any? {|char| !pred(char) }

... и, наконец, мы можем поместить логи c обратно в блок:

char_list.any? {|char| !(utf8?(char) && char.blank?) }

Как вы можете видеть, вы были почти у цели, но вместо того, чтобы просто отрицать char.blank?, вам нужно было свести на нет все выражение внутри блока.

...