Ruby Acronym Creator из строки - PullRequest
1 голос
/ 13 июля 2020

Я создаю функцию, которая принимает строку и создает аббревиатуру, но у меня возникают ошибки. Когда я ввожу "Complementary metal-oxide semiconductor", я получаю "CS" взамен, ожидая "CMOS". Есть предложения, почему это могло произойти? Я передаю ему множество других строк, и он работает, только в этом случае не работает.

class Acronym

    def self.abbreviate(phrase)
        letters = phrase.split("")
        acronym = []
        letters.each do |letter|
            previous = letters.index(letter) - 1
            if previous == -1
                acronym.push(letter)
            elsif letters[previous] == " " || letters[previous] == "-"
                acronym.push(letter)
            end
        end
        acronym.join("").upcase
    end

end

Ответы [ 4 ]

4 голосов
/ 13 июля 2020

Упрощается до

def acronym(str)
  str.split(/ |-/).map(&:first).join.upcase
end

Вышеуказанное зависит от библиотеки activesupport Rails. Вот только вариант Ruby:

str.split(/ |-/).map { |s| s[0] }.join.upcase 
2 голосов
/ 13 июля 2020

Проблема с вашим кодом заключается в том, что index() возвращает первое вхождение данной буквы. Итак, две проблемы:

  1. 'm' в 'metal' не является первым появлением 'm' в строке. Он встречается в слове «дополнительный». Таким образом, всякий раз, когда он видит 'm' в строке, предыдущий всегда будет 'o' и, следовательно, не вызовет push().
  2. Каждый раз, когда первая буква в вашей строке повторяется (независимо от позиции), он вызовет ваше первое состояние. Вы можете увидеть эффект, если измените начальное «C» на «c» в тестовой строке. Результатом будет CSCC, потому что в «semiconductor» есть два 'c'.

В качестве альтернативы вот вариант, использующий регулярное выражение:

def self.abbreviate(phrase)
  phrase.gsub('-', ' ')
        .scan(/(\A\w|(?<=\s)\w)/)
        .flatten
        .join.upcase
end

Пошагово:

  1. Заимствование .gsub у @DollarChills, чтобы превратить '-' в пробел.
  2. scan() возвращает массив всех совпадений. Регулярное выражение соответствует первому слову в строке и любому слову, которому предшествует пробел.
  3. Результатом scan на самом деле является массив массивов, поэтому при сглаживании их раскладывается.
  4. Объединить в строку и упаковать
2 голосов
/ 13 июля 2020

Вы можете попробовать использовать gsub , чтобы игнорировать дефис.

<%= ('Complementary metal-oxide semiconductor').gsub('-', ' ') %>

Возвращает: Дополнительный металлооксидный полупроводник

1 голос
/ 13 июля 2020

У вас есть ошибка в previous = letters.index(letter) - 1

, посмотрите, сможете ли вы ее обнаружить:

arr = [:a, :b, :c, :a]
previous_indexes = arr.map { |n| arr.index(n) - 1 }
you_are_expecting = [-1, 0, 1, 2]

previous_indexes == you_are_expecting
# => false

arr.index(:a) # => 0
arr.index(:b) # => 1
arr.index(:c) # => 2
arr.index(:a) # => 0

Чтобы получить индексы с итерацией, используйте with_index:

arr = %i[a b c a]
arr.map.with_index { |x, i| [x, i] }
# => [[:a, 0], [:b, 1], [:c, 2], [:a, 3]]

Если вы сделаете это исправление, ваш код сделает то, что вы планировали.

Тем не менее, совет: часто можно избежать работы с деталями индексов массивов. Посмотрите, как работает @ Mori answer , работая на более высоком уровне.

...