2016-01-26 3 views
0

Я пытаюсь изучить Ruby с материалом Test-First, и я застрял на этом этапе. Это мой код:моя программа цикла бесконечно при назначении определенной строки переменной, и я не могу понять, почему

def translate(word) 
    word=word.split("") 
    while (!vowel(word[0])) do 
    first_letter=word[0] 
    word.each_index do |i| 
     word[i]=word[i+1] 
    end 
    word[word.length-1]=first_letter 
    end 

    return word.join + "ay" 
end 

def vowel(letter) 
    if letter == ("a" || "e" || "i" || "o" || "u") 
    return true 
    end 
end 

Цель состоит в том, чтобы реализовать функцию, которая переводит слово «свинья латино», посмотрев, если слово начинается с гласной. Если это так, функция просто добавляет «ay». Если он начинается с согласного, он помещает первую букву в конце слова, пока в первой позиции не будет гласного.

У меня проблема начинается при назначении первого письма, которое я сохранил в начале цикла в то время как, к последней позиции слова, с

word[word.length-1]=first_letter

Это заставляет программу цикла на неопределенный срок.

Тест основан на строке «банан», после обработки следует читать «ananabay». В этом случае first_letter содержит «b». Поэтому я тестировал назначение разных букв на последнюю позицию слова, все, кроме «b», отлично работает. То, что я не понимаю, заключается в том, что с блоком while, не зависящим от последней буквы, но на первой букве слова, он все еще вызывает неопределенный цикл, назначая «b» слову [word.length-1].

Я был бы очень благодарен за понимание.

+3

Вы не написать тест для метода 'vowel', не так ли? – Stefan

+0

Нет, метод гласных не был в спецификации, но я думал, что это будет более структурировано таким образом. –

+1

Это * более структурировано таким образом, но тест показал бы, что ваш метод работает не так, как ожидалось: 'vowel ('e') # => nil' – Stefan

ответ

2

Обратите внимание, что

letter == ("a" || "e" || "i" || "o" || "u") 

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

letter == "a" 

как ("a" || "e" || "i" || "o" || "u") будет оценивать к первому truthy значение, которое случается в этом случае "a".

Что вам нужно

(letter == "a") || (letter == "e") || (letter == "i") || (letter == "o") || (letter == "u") 

, который также может быть записана в виде:

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

или

%w(a e i o u).include?(letter) 

или

"aeiou".chars.include?(letter) 

В связи с упомянутой выше логической ошибкой, метод vowel вернет nil всякий раз, когда письмо не "a", и если есть слово, которое не содержит гласное a, то цикл while никогда не заканчивается. Следовательно, его нужно скорректировать на что-то вроде ниже. Кроме того, пока мы на нем, давайте добавим ? к имени метода, чтобы указать, что оно вернет логическое значение.

def vowel?(letter) 
    "aeiou".chars.include?(letter) 
end 

Перемещение первого символа строки до конца строки также может быть упрощена с помощью кода, как показано ниже:

word = word[1..-1].concat(word[0]) 

Позволяет извлечь эту логику в новый метод:

def rotate(word) 
    word[1..-1].concat(word[0]) 
end 

Вы также можете si mplify цикл while путем переключения на выражение until.

word = rotate(word) until vowel?(word.chars.first) 

Таким образом, ваш метод translate может быть упрощена к чему-то, как показано ниже:

def translate(word) 
    word = rotate(word) until vowel?(word.chars.first) 
    word.concat("ay") 
end 

Существует еще один вопрос, что происходит со словами, которые не имеют каких-либо гласные, то цикл будет быть бесконечным циклом. Нам нужно исправить это

def translate(word) 
    if word.chars.any? { |i| vowel?(i) } 
    word = rotate(word) until vowel?(word.chars.first) 
    end 
    word.concat("ay") 
end 

Полный код:

def translate(word) 
    if word.chars.any? { |i| vowel?(i) } 
    word = rotate(word) until vowel?(word.chars.first) 
    end 
    word.concat("ay") 
end 

def rotate(word) 
    word[1..-1].concat(word[0]) 
end 

def vowel?(letter) 
    "aeiou".chars.include?(letter) 
end 


p translate("banana") 
#=> "ananabay" 

p ["pig", "banana", "trash", "happy", "duck", "glove"].map(&method(:translate)) 
#=> ["igpay", "ananabay", "ashtray", "appyhay", "uckday", "oveglay"] 
+0

Вы также можете извлечь 'word [1 ..- 1] .concat (слово [0])' в отдельный метод 'rotate (str)' – Stefan

+0

@Stefan Ницца, позвольте мне сделать это - слишком плохо, нет такой метод уже - я искал его. –

 Смежные вопросы

  • Нет связанных вопросов^_^