単語を逆にし、母音を動かし、すべてを小文字にします
私はRubyを初めて使用します。
この関数は、任意の数の単語の文字列を受け取り、単語の順序を逆にします。また、単語ごとに、母音を取得して単語の最後に移動します。また、すべてをダウンケースします。したがって、Hello World!
になりwrld!o hlleo
ます。
私はいくつかのRuby機能を使おうとしているので、いわばワンライナーである理由です。基本的に私はスタイルの提案を探しています。このようにするのが適切ですか(1行?)。私のコードは非常に長く複雑なので、タスクをより速く実行できる関数があると確信しています。私もそれらの提案を受け入れます。また、これをベースのRubyのみで記述し、追加のパッケージ/ gemは使用しないようにしたいと思います。
誰かが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年後に何を言いますか?
これは、(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
ソリューションは次のことを行います。
- 文字列を小文字にする
- 結果の文字列を単語の配列に変換します
- 単語の配列を逆にする
- 配列内の各単語を変換して、母音が最後になり、母音と非母音の両方の順序が保持されるようにします。
- 結果の配列内の単語を結合して文字列を形成します
最後から2番目の操作から始めましょう。コードをより読みやすくし、テストを高速化するために、それを別のメソッドにしましょう。
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
Enumerator#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`