2016-10-21 1 views
1

Кажется, что RubyMine IDE сигнализирует предупреждение, когда видит отрицательную условную инструкцию. Мне интересно, почему использование отрицательного условного утверждения плохое? Это просто из-за читаемости?Отрицательный условный оператор в Ruby

Например, в этом коде:

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?) в этом случае?

+0

Вы можете написать инструкцию 'case'' dna_complement << case strand; когда «C» затем «G»; когда «G» затем «C»; когда «Т» затем «А»; когда «A» затем «U»; end'. В качестве альтернативы вы можете написать 'dna_complement << strand.tr (« CGTA »,« GCAU »)'. –

ответ

5

Поскольку Руби не только 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, но это создает тройной негатив. Вы уже имеете дело с двойным здесь, предложение 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 на самой строке, метод, оптимизированный для обработки таких вещей, как cyphers, где есть сопоставление 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' будет более эффективным, чем версия массива того же самого, особенно учитывая, что массив будет содержать N строк, каждый из которых несет некоторые накладные расходы, и требует создания другой строки в конце, используя join. При использовании Ruby попытайтесь сохранить количество объектов, необходимых для выполнения ваших вычислений, временных или иных, до минимума. Это обычно быстрее с меньшим количеством «мусора».

+0

ваш ответ doubleplusgood для показа альтернативы описанию дела! –

+1

@tadman Вау, большое вам спасибо. Вы не только ответили на мой вопрос, но и дали много ценных советов. Теперь я буду реорганизовывать свой код. –

+0

@tadman Не могли бы вы также объяснить мне регулярное выражение? Я не понимаю, что означают '\ A' и' \ z' в начале и в конце регулярного выражения. –

1

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

В любом случае, это точно так же.

0

Я думаю, что это лошади для курсов ... Я работал с очень хорошими разработчиками, чей первый язык не английский, и они находят If ! (если нет) легче понять.

Но стиль руководство Руби https://github.com/bbatsov/ruby-style-guide специально предпочитает unless к if ! но хмурится Upon unless используется с else.

Наконец, лучше переписать в виде одной линии с задним условным ...

return '' unless dna_structure.include? strand