#ruby #syntax #conditional
#ruby #синтаксис #условные операторы
Вопрос:
Похоже, что среда разработки RubyMine выдает предупреждение всякий раз, когда видит отрицательный условный оператор. Мне интересно, почему использование отрицательного условного оператора плохо? Это просто из-за удобства чтения?
Например, в этом коде:
class Complement
def self.of_dna dna_strand
dna_array = dna_strand.chars
dna_complement = ['']
dna_structure = ['C', 'G', 'T', 'A']
dna_array.each do |strand|
unless dna_structure.include? strand
return ''
end
case strand
when "C"
dna_complement << "G"
when "G"
dna_complement << "C"
when "T"
dna_complement << "A"
when "A"
dna_complement << "U"
end
end
dna_complement.join('')
end
end
Мне интересно, в чем разница между unless dna_structure.include? strand
и if !(dna_strucutre.include?)
в этом случае?
Комментарии:
1. Вы могли бы написать свой
case
операторdna_complement << case strand; when "C" then "G"; when "G" then "C"; when "T" then "A"; when "A" then "U"; end
. В качестве альтернативы вы могли бы написатьdna_complement << strand.tr("CGTA", "GCAU")
.
Ответ №1:
Поскольку в Ruby есть не только if
, но unless
, рекомендуется использовать его до тех пор, пока результирующий код понятен. То есть вы должны преобразовать что-то вроде этого:
if (!string.empty?)
# ...
end
Во что-то вроде этого:
unless (string.empty?)
# ...
end
Для этого есть исключения, например, когда у вас есть это:
if (!string.empty?)
# ... when not empty
else
# ... when empty (when not not empty)
end
Наивным подходом было бы преобразовать это в unless
, но это создает тройное отрицание. Здесь вы уже имеете дело с double, else
предложение выполняется только в том случае, если строка не пустая или, возможно, ничего не не не не содержит, не не не не не содержит, не не не не не содержит. не не не не не содержит. не не не не не содержит.
Сделайте это вместо:
if (string.empty?)
# ... when empty
else
# ... when not empty
end
Существует ряд проблем с подходом, который вы используете здесь, но самая серьезная из них заключается в том, что вы объявляете постоянный массив внутри вашего метода каждый раз, когда метод вызывается. Поскольку это никогда не меняется, сделайте это константой на верхнем уровне класса. По крайней мере:
class Complement
DNA_STRUCTURE = %w[ C G A T ]
end
Еще лучше было бы использовать таблицу сопоставления для представления пар:
COMPLEMENT = {
'C' => 'G',
'G' => 'C',
'T' => 'A',
'A' => 'U'
}.freeze
Теперь, глядя на вашу конкретную проблему, когда вы пытаетесь «инвертировать» заданную последовательность символов, инструмент, который вам действительно нужен, находится tr
в самой строке, метод, который оптимизирован для обработки таких вещей, как шифры, где между символами есть сопоставление 1: 1.
Вся ваша функция сворачивается до этого:
def self.of_dna(strand)
strand.tr('CGTA', 'GCAU')
end
Теперь, если вы хотите выполнить быстрый тест, чтобы убедиться, что вы действительно имеете дело с допустимой последовательностью:
def self.of_dna(strand)
return '' unless (strand.match(/A[CGTA]*z/))
strand.tr('CGTA', 'GCAU')
end
Здесь вы сталкиваетесь с некоторыми другими вредными привычками, такими как создание массивов для хранения отдельных символов, когда строки намного лучше справляются с этой конкретной задачей. c = ''
и тогда c << 'G'
было бы эффективнее, чем массивная версия same, особенно учитывая, что массив будет содержать N строк, каждая из которых несет некоторые накладные расходы и требует создания другой строки в конце с помощью join
. При использовании Ruby старайтесь свести количество объектов, необходимых для выполнения ваших вычислений, временных или иных, к минимуму. Обычно это быстрее с меньшим количеством «мусора».
Комментарии:
1. ваш ответ вдвойне хорош за то, что вы показали альтернативу оператору case!
2. @tadman Вау, большое тебе спасибо. Вы не только ответили на мой вопрос, но и дали много ценных советов. Сейчас я проведу рефакторинг своего кода.
3. @tadman Не могли бы вы также, пожалуйста, объяснить мне регулярное выражение? Я не понимаю, что
A
иz
означает в начале и в конце регулярного выражения.4. Если вы не знакомы с регулярными выражениями, загляните на такой сайт, как Rubular , чтобы получить пояснения и простой способ запуска тестов.
Ответ №2:
В последней форме нет ничего плохого, но, учитывая, что в ruby у нас есть unless
, мы должны использовать ее, когда у нас есть только одна ветвь, и это предпочтительнее, как в этом случае.
В любом случае, это точно то же самое.
Ответ №3:
Я думаю, что это лошади для курсов… Я работал с очень хорошими разработчиками, чей родной язык не английский, и они находят If !
(если нет) более легким для понимания.
Но руководство по стилю Ruby https://github.com/bbatsov/ruby-style-guide определенно предпочитает unless
if !
, но не одобряет unless
использование с else
.
Наконец, лучше переписать как однострочный с завершающим условным выражением…
return '' unless dna_structure.include? strand