Конечно, оригинальная «Одиссея» была написана греческим поэтом, но римляне свободно заимствовали у своих средиземноморских братьев и сестер, и мне не стыдно поступать так же. На протяжении своей карьеры я много писал - информационные бюллетени, электронные письма для массового распространения и т. Д. Но почти во всех этих случаях мне было комфортно знать, что я знаю больше (или, по крайней мере, столько же) о моем предметном материале. как и любой из моих вероятных читателей. Это почти наверняка не относится к этому блогу, поэтому в этом смысле он выходит на новую территорию. Так что мне просто нужно принять поговорку, вышитую на передней части одной из моих футболок: «Все, что я говорю, полностью подтверждается моим собственным мнением!»

Зачем писать код?

Возможно, перед тем, как перейти к рассказу, уместно сделать небольшую предысторию. Хотя у меня был некоторый ранний опыт работы с компьютерами (первый класс по программированию я пошел в 11 лет), большую часть своей карьеры я провел в управлении капиталом. Во многих отношениях это было очень приятно. Поскольку почти любое событие могло повлиять на мою работу, я никогда не знал, что может принести любой день. Но это также означало, что почти все было бессрочным. Но с кодированием, хотя может быть несколько способов чего-то достичь (подробнее об этом позже), в конце концов, ваш код работает или нет. Полная остановка. Сложность, связанная с этим, очень нравится ребенку, который любил геометрические доказательства в школе или получил отличную оценку в части логических игр в LSAT.

Белая доска

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

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

Решение - в первый раз

Первым шагом к решению было осознание того, что римляне обрабатывали каждый столбец в нашей системе нумерации отдельно. Таким образом, число, оканчивающееся на 9, всегда будет заканчиваться на IX, независимо от того, 9, 19, 129 или 1099. Логика внутри каждого столбца одинакова, меняются только буквы. Например, логика XXX (30) такая же, как III (3).

Оттуда ключевыми моментами было выяснить, сколько цифр было в номере, и уметь извлекать каждую цифру индивидуально. Затем я использовал серию if / elsif, чтобы определить «римское» значение каждой цифры и добавить каждый сегмент в строку результата. Один небольшой фрагмент кода (имеющий отношение к столбцу сотен) показан ниже:

if @number.to_i > 99
    if hundreds_digit == 0
    elsif hundreds_digit < 4
      hundreds_digit.times do 
        roman_numeral += "C"
      end
    elsif hundreds_digit == 4
      roman_numeral += "CD"
    elsif hundreds_digit < 9
      roman_numeral += "D"
      if hundreds_digit > 5
        (hundreds_digit - 5).times do
          roman_numeral += "C"
        end
      end
    else
      roman_numeral += "CM"
    end
  else
  end

После небольшой отладки я был в восторге от того, что код заработал. По предложению инструктора я поделился им с группой. Некоторое время спустя она вернулась со словами: «Отлично. А как насчет Шага 7? Как бы вы его реорганизовали? » Я смотрел на экран в течение нескольких минут, возможно, бормоча себе пару фраз NSFW, думая про себя, рефакторинг? Я только что решил это и заставил работать. Как, черт возьми, я собираюсь что-то менять? Если бы у меня были идеи получше, я бы с самого начала поступил именно так. Выполнив за это время еще одно сложное (по крайней мере для меня) упражнение, я сильно разжарился и решил закончить его.

Решение…. снова

На следующий день я снова подумал о проблеме. И подумал о логике, которую я использовал, чтобы сначала это сломать. Я все время возвращался к той части, что логика каждого столбца одинакова. Это ужасно похоже на то, для чего нужен цикл. Тогда я подумал, почему бы не создать массив, похожий на таблицу поиска. Я мог использовать столбец, в котором находился, как одну индексную переменную, а фактическую цифру этого столбца - как вторую. С этим пониманием мои почти 100 строк кода превратились в 24 (полностью представлены ниже).

def roman_numeral(number)
  @number = number.to_s
  length = @number.length
  roman_numeral = ""
roman_array = [["", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"], ["", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"], ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"], ["", "M", "MM", "MMM", "MMMM"]]
i = 0
  length.times do
    i2 = @number[length - (i + 1)].to_i
    roman_digit = roman_array[i][i2]
    roman_numeral.insert(0, roman_digit)
    i += 1
  end
if roman_numeral == ""
    puts "The Romans did not have the concept of zero as a number but used the word nulla"
  else
    puts roman_numeral
  end
end
roman_numeral(2018) # => MMXVIII

Вывод из этого упражнения для меня состоит в том, что почти всегда есть лучший, более эффективный и элегантный способ что-то сделать. То, что что-то работает, не означает, что это нельзя улучшить. Как и сами римские цифры.