Inverser les mots, déplacer les voyelles et tout mettre en minuscules
Je suis tout nouveau sur Ruby.
La fonction prend une chaîne de n'importe quel nombre de mots et inverse l'ordre des mots. De plus, pour chaque mot, il prend les voyelles et les déplace à la fin du mot. Cela minimise également tout. Ainsi, Hello World!
deviendrait wrld!o hlleo
.
J'essaie d'utiliser certaines fonctionnalités de Ruby, d'où la raison pour laquelle il s'agit d'une ligne pour ainsi dire. Fondamentalement, je cherche juste des suggestions de style. Est-il approprié de faire une telle chose de cette manière (une ligne ?). Je suis sûr qu'il existe des fonctions qui pourraient accomplir la tâche plus rapidement, donc je suis également ouvert à ces suggestions, car mon code est très long et compliqué. Je dois également mentionner que je voulais écrire ceci avec uniquement Ruby de base, pas de packages/gemmes supplémentaires.
Quelqu'un a suggéré Rubocop et le guide de style, je vais donc les vérifier.
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
Réponses
Les one-liners sont très amusants, mais le monde n'en a pas vraiment besoin de plus. Cela dit, ils ne doivent pas être si illisibles. Que dira votre futur cerveau dans un an si vous devez maintenir cette fonction ?
Voici une approche illustrant une technique évolutive pour rendre lisible même les longs "one-liners" en (1) utilisant généreusement les lignes, (2) indentant le code à la manière d'une structure de données joliment imprimée pour transmettre la hiérarchie de la logique (le code est une donnée, après tout), et (3) inclure des commentaires pour aider le lecteur avec la logique et l'intention.
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
Votre solution effectue les opérations suivantes :
- mettre la chaîne en minuscule
- convertir la chaîne résultante en un tableau de mots
- inverser le tableau des mots
- convertir chaque mot du tableau de sorte que les voyelles soient à la fin et que l'ordre soit préservé pour les voyelles et les non-voyelles
- joindre les mots dans le tableau résultant pour former une chaîne
Commençons par l'avant-dernière opération. Pour rendre le code plus lisible et accélérer les tests, faisons-en une méthode distincte.
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
Voir String#each_char , String#include? et String#join .
A part : j'aurais pu écrire à la word.chars do |char|...
place de word.each_char do |char|...
, mais le premier a l'inconvénient de word.chars
retourner un tableau intermédiaire, alors que le second retourne un énumérateur, consommant ainsi moins de mémoire.
Essayons:
shove_vowels_to_end("atlastdisgonehurray!")
#=> "tlstdsgnhrry!aaioeua"
Si vous le souhaitez, nous pourrions créer VOWELS
un ensemble (pour employer Set#include? , ce qui peut accélérer un peu les calculs :
require 'set'
VOWELS = 'aeiou'.each_char.to_set
#<Set: {"a", "e", "i", "o", "u"}>
On peut maintenant écrire le reste de la méthode autour de shove_vowels_to_end
:
def funky_words(str)
str.downcase.split.map { |word| shove_vowels_to_end(word) }.join(' ')
end
Je vais discuter du code mais essayons d'abord:
str = "Little Miss Muffett sat on her tuffet"
funky_words str
#=> "lttlie mssi mffttue sta no hre tfftue"
Selon ce que l'on sait str
, nous devrons peut-être passer str.split
à str.strip.split
. str.split
est identique à str.split(/\s+/)
, ce qui est probablement approprié. Voir String#split .
Le calcul intermédiaire est :
str.downcase.split.map { |word| shove_vowels_to_end(word) }
#=> ["lttlie", "mssi", "mffttue", "sta", "no", "hre", "tfftue"]
c'est pourquoi nous avons besoin .join(' ')
à la fin.
Notez que les espaces supplémentaires ne sont pas conservés :
funky_words "some spaces"
#=> "smoe spcsae"
Voici une manière d'écrire plus proche de 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
Voir Enumérateur#with_object .
Remarquez comment j'ai utilisé la décomposition de tableau à l'avantage lors de l'écriture des variables de bloc :
|char, (non_vowels, vowels)|
Voici une autre façon d'écrire funky_words
. Je modifie chaque séquence de non-espaces avec 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"
Envisagez de modifier le mot 'muffett'
. C'est devenir 'mffttue'
. Cependant, puisque j'inverse la chaîne à la fin, je dois convertir 'muffett'
en 'muffett'.reverse #=> 'euttffm'
. Cela s'obtient dans les étapes suivantes :
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`