Переверните слова, переместите гласные и уберите все
Я новичок в Руби.
Функция принимает строку из любого количества слов и меняет порядок слов. Кроме того, для каждого слова он берет гласные и перемещает их в конец слова. Это тоже все опускает. Таким образом, Hello World!
стало бы wrld!o hlleo
.
Я пытаюсь использовать некоторые функции Ruby, поэтому, так сказать, однострочно. В основном я просто ищу предложения по стилю. Уместно ли это делать таким образом (одной строкой?). Я уверен, что есть функции, которые могут решить эту задачу быстрее, поэтому я тоже открыт для этих предложений, поскольку мой код очень длинный и запутанный. Также я должен упомянуть, что хотел написать это только на базовом Ruby, без дополнительных пакетов / гемов.
Кто-то предложил Rubocop и руководство по стилю, так что я их проверю.
def funky_words(s)
s.strip.gsub(/\s+/, " ").split(" ").reverse.instance_eval{map{|elt| elt.gsub(/([aeiou])/i,"")}}.
zip(s.strip.split(" ").reverse.map{|elt| elt.scan(/([aeiou])/i).flatten}.instance_eval{map{|elt| elt.join}}).
map(&:join).join(" ").downcase
#first "line" reverses word order removes vowels, second "line" captures vowels, last "line" joins vowels and all words
end
Ответы
Однострочники - это хорошее развлечение, но на самом деле миру их не нужно. Тем не менее, они не должны быть такими нечитаемыми. Что скажет ваш будущий мозг через год, если вам придется поддерживать эту функцию?
Вот подход, иллюстрирующий масштабируемую технику, позволяющую сделать даже длинные «однострочные» читаемыми с помощью (1) большого количества строк, (2) отступов в коде в виде красиво напечатанной структуры данных для передачи иерархии логики (код - это данные, в конце концов), и (3) включая комментарии, чтобы помочь читателю понять логику и намерения.
def funky_words(s)
(
# Split into words.
s
.split
.reverse_each
.map { |word|
# Within each word, push vowels to the end, while preserving
# original order within consonants and vowels.
word
.each_char
.sort_by.with_index { |c, i| "aeiouAEIOU".include?(c) ? [1, i] : [0, i] }
.join
}
# Rejoin the new words.
.join(" ")
)
end
Ваше решение делает следующее:
- опустить строку
- преобразовать полученную строку в массив слов
- перевернуть массив слов
- преобразовать каждое слово в массиве так, чтобы гласные были в конце, а порядок сохранялся как для гласных, так и для негласных
- объединить слова в результирующем массиве, чтобы сформировать строку
Начнем с предпоследней операции. Чтобы сделать код более читабельным и протестировать скорость, сделаем это отдельным методом.
VOWELS = 'aeiou'
def shove_vowels_to_end(word)
vowels = ''
non_vowels = ''
word.each_char do |char|
if VOWELS.include?(char)
vowels << char
else
non_vowels << char
end
end
[non_vowels, vowels].join
end
См. String # each_char , String # include? и String # join .
Кроме того: я мог бы написать word.chars do |char|...
вместо word.each_char do |char|...
, но у первого есть недостаток, который word.chars
возвращает промежуточный массив, тогда как последний возвращает перечислитель, тем самым потребляя меньше памяти.
Давай попробуем:
shove_vowels_to_end("atlastdisgonehurray!")
#=> "tlstdsgnhrry!aaioeua"
При желании мы могли бы сделать VOWELS
набор (чтобы использовать Set # include?, Который может немного ускорить вычисления:
require 'set'
VOWELS = 'aeiou'.each_char.to_set
#<Set: {"a", "e", "i", "o", "u"}>
Теперь мы можем написать остальную часть метода shove_vowels_to_end
:
def funky_words(str)
str.downcase.split.map { |word| shove_vowels_to_end(word) }.join(' ')
end
Я буду обсуждать код, но сначала попробуем:
str = "Little Miss Muffett sat on her tuffet"
funky_words str
#=> "lttlie mssi mffttue sta no hre tfftue"
В зависимости от того, что о нем известно, str
нам может потребоваться перейти str.split
на str.strip.split
. str.split
то же самое str.split(/\s+/)
, что, вероятно, уместно. См. Раздел String # split .
Промежуточный расчет:
str.downcase.split.map { |word| shove_vowels_to_end(word) }
#=> ["lttlie", "mssi", "mffttue", "sta", "no", "hre", "tfftue"]
вот почему нам нужно .join(' ')
в конце.
Обратите внимание, что лишние пробелы не сохраняются:
funky_words "some spaces"
#=> "smoe spcsae"
Вот способ написания, более похожий на Ruby shove_vowels_to_end
:
def shove_vowels_to_end(word)
word.each_char.with_object(['', '']) do |char, (non_vowels, vowels)|
if VOWELS.include?(char)
vowels << char
else
non_vowels << char
end
end.join
end
См. Перечислитель # with_object .
Обратите внимание, как я успешно использовал декомпозицию массива при записи блочных переменных:
|char, (non_vowels, vowels)|
Вот еще один способ написать funky_words
. Я изменяю каждую последовательность непробелов с помощью String # gsub .
require 'set'
VOWELS = %w|a e i o u|.to_set
#=> #<Set: {"a", "e", "i", "o", "u"}>
def funky_words(str)
str.downcase.gsub(/[^ ]+/) do |word|
vowels = ''
others = ''
word.each_char do |char|
if VOWELS.include?(char)
vowels.prepend(char)
else
others.prepend(char)
end
end
others + vowels
end.reverse
end
str = "Little Miss Muffett sat on her tuffet"
funky_words(str)
#=> "tfftue hre no sta mffttue mssi lttlie"
Попробуйте изменить слово 'muffett'
. Это должно стать 'mffttue'
. Однако, поскольку я переворачиваю строку в конце, мне нужно преобразовать ее 'muffett'
в 'muffett'.reverse #=> 'euttffm'
. Это достигается следующими шагами:
muffett
vowels = ''
others = 'm'
uffett
vowels = 'u'
others = 'm'
ffett
vowels = 'u'
others = 'fm'
fett
vowels = 'u'
others = 'ffm'
ett
vowels = 'eu'
others = 'ffm
tt
vowels = 'eu'
others = 'tffm'
t
vowels = 'eu'
others = 'ttffm'
vowels + others
#=> `euttffm`