2017-02-05 7 views
0

Вот мой код:Ruby проверяет только первый элемент булевого выражения?

array = ["b", "c", "a", "e", "d", "g", "i", "f"] 
array.each_index do |letter| 
    if array[letter] == ("a" || "e" || "i" || "o" || "u") 
    puts "found #{array[letter]}" 
    end 
end 

Я бы ожидать, что она вернется так:

found a 
found e 
found i 

, но вместо этого я получаю только

found a 

Более того, если бы я изменить порядок элементы внутри() в строке 3, например как этот

if array[letter] == ("e" || "a" || "i" || "o" || "u") 

код возвращает found e вместо found a.

Я думаю, что я понимаю проблему. Ruby проверяет только array на первый элемент внутри(). Но может ли кто-нибудь объяснить, почему это так? Я ожидаю, что он проверит их всех.

ответ

2

x || y является x если x является правдой, y в противном случае. "a" является truthy (все, кроме nil и false является truthy, те два и только эти двое falsey), поэтому "a" || whatever_it_doesnt_matter является всегда"a".

Так,

if array[letter] == ("a" || "e" || "i" || "o" || "u") 

эквивалентно

if array[letter] == ("a" || ("e" || ("i" || ("o" || "u")))) 

, который принимает значение

if array[letter] == ("a" || ("i" || ("o" || "u"))) 

, который принимает значение

if array[letter] == ("a" || ("o" || "u")) 

, который вычисляет

if array[letter] == ("a" || "u") 

, который оценивает в

if array[letter] == "a" 
+1

Плюс '||' короткое замыкание, поэтому вам не нужно выходить за пределы '(" a "|| (...))'. – pjs

+0

Я ожидаю, что комментарий @ pjs направлен на ваш выбор слова «оценивает». –

3

булева утверждение логически неправильно. Это должно быть

array[letter] == "e" || array[letter] == "a" || array[letter] == "i" || array[letter] == "o" || array[letter] == "u" 

Или более идиоматических

["a" , "e" , "i" , "o" ,"u"].include?(array[letter]) 
1

Смотрите объяснение от @ JörgWMittag, почему ваш код не работает.

Вы могли бы написать:

array = %w(b c a e d g i f) 

vowels = %w(a e i o u) 
array.each do |letter| 
    puts "found #{letter}" if vowels.include? letter 
end 

или просто:

array.grep(/[aeiou]/).each do |vowel| 
    puts "found #{vowel}" 
end 

Обратите внимание, что поскольку Рубин является динамичным, имена переменных очень важны.

Это синтаксически корректен:

array.each_index do |letter| 

но это дает неправильное впечатление, что letter является строкой с письмом внутри.