Quelle est la manière la plus simple de créer un tableau de x quantité d'éléments composés de types de données mixtes (c'est-à-dire, un tableau avec des chaînes, des entiers et des flottants) à partir de l'entrée utilisateur
Jusqu'à présent, j'ai créé du code qui fonctionnait en utilisant un pour la boucle, mais je voulais savoir s'il y avait un moyen de l'optimiser et d'avoir le moins de lignes de code.
puts "how many elements?"
max = gets.to_i
array = []
for i in 0..max - 1
puts "are you entering in a string, an int or a float?"
data_type = gets.chomp
if %W[string STRING String s S].include?(data_type)
puts "enter in a string"
array[i] = gets.chomp
elsif %W[int INT Int i I].include?(data_type)
puts "enter an int"
array[i] = gets.to_i
elsif %W[Float FLOAT float f F].include?(data_type)
puts "enter a float"
array[i] = gets.to_f
end
end
print array
5 Réponses :
Nombre minimum de lignes? Une. Une fois que vous avez max:
array = max.times.map { gets.chomp.then { |l| Integer(l) rescue Float(l) rescue l } }
C'est encore plus court (bien que certaines personnes s'y opposent):
array = max.times.map { gets.chomp.then { |l| case l when /^\d+$/ then l.to_i when /^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$/ then l.to_f else l end } }
Cependant, il serait plus lisible de l'écrire en plusieurs lignes.
Notez également que les rubisistes prétendent essentiellement que pour n'existe pas dans la langue, et le remplacera généralement par Enumerable # each , Integer # times et similaire.
Ce n'est pas tout à fait la même chose que ce que vous avez; mon code rend impossible d'avoir une chaîne qui serait un nombre valide, comme par exemple "2.0" . Votre code n'est pas trop mauvais si vous voulez cette fonctionnalité (et l'obsession du nombre de lignes est généralement malavisée). Les choses que je changerais:
Boucle. array = max.times.map do ... end over for à tout moment. (Cela rend également une attribution explicite au array [i] inutile.)
"float" .start_with? (data_type.downcase) au lieu de % W [Float FLOAT float f F] .include? (data_type) , donc vous n'avez pas à vous soucier de répertorier toutes les variantes.
"Les rubisistes prétendent fondamentalement que cela n'existe pas" - de quoi s'agit-il pour dont vous parlez?
@Stefan, quelle est la source de ces mots éclairés? Un vieil homme sage de l'est (de Delmenhorst)?
Sans changer de comportement en dehors d'accepter string , int et float comme insensibles à la casse (par exemple. stRinG fonctionne également) vous pouvez faire quelque chose comme ceci.
case gets when # ... #... else redo end
Remarque: Vous pouvez ajouter un else dans le case -déclaration, pour gérer le scénario selon lequel l'utilisateur n'entre pas string , int ou float . Actuellement, cela entraînera une valeur nil dans le tableau.
Vous voudrez peut-être l'implémenter de la manière suivante:
puts "how many elements?"
max = gets.to_i
array = max.times.map do
puts "are you entering in a string, an int or a float?"
case gets
when /\A(string|s)\Z/i
puts "enter in a string"
gets.chomp
when /\A(int|i)\Z/i
puts "enter an int"
gets.to_i
when /\A(float|f)\Z/i
puts "enter a float"
gets.to_f
end
end
print array
Il n'est peut-être pas évident d'implémenter une partie else fonctionnelle avec max.times.map - peut-être devriez-vous l'ajouter à votre réponse.
Astuce: else redo ( redo est tellement sous-estimé ...)
Oui, j'y pensais moi-même. Ajouté à la réponse.
Utilisation d'un Hash comme aide:
datatypes = { i: { convert: 'to_i', text: 'an integer' }, f: { convert: 'to_f', text: 'a float' } }
datatypes.default = { convert: 'to_s', text: 'a string' }
array = max.times.map do
puts "Are you entering in an (i)nt, a (f)loat or a string (default)?"
data_type = gets[0].downcase.to_sym # you can improve this part
puts "enter in #{datatypes[data_type][:text]}"
gets.chomp.send(datatypes[data_type][:convert])
end
p array
p array.map &:class
OK, je vais mordre.
p Array.new(puts("How many elements?") || gets.to_i) { puts("Are you entering in a string, an int or a float?") || case(gets.chomp) when "string", "S" then (puts("Enter a string") || gets.chomp) when "int", "INT" then (puts("Enter an integer") || gets.to_i) when "float", "F" then (puts("Enter a float") || gets.to_f) end }
La boîte de dialogue suivante:
[5, "hi", 3.4]
entraîne l'affichage de ce qui suit (et le retour ):
How many elements?: 3 Are you entering in a string, an int or a float?: int Enter an integer: 5 Are you entering in a string, an int or a float?: S Enter a string: hi Are you entering in a string, an int or a float?: F Enter a float: 3.4
J'ai utilisé p plutôt que met (qui afficherait les éléments de ce tableau un par ligne) pour indiquer clairement que c'est un tableau qui est affiché. Notez que chaque met dans les retours extraits nil , donc nil || x # => x .
Cet extrait de code comporte huit lignes, mais il peut être réduit à une en supprimant les nouvelles lignes:
p Array.new(puts("How many elements?") || gets.to_i) {
puts("Are you entering in a string, an int or a float?") ||
case(gets.chomp)
when "string", "S" then (puts("Enter a string") || gets.chomp)
when "int", "INT" then (puts("Enter an integer") || gets.to_i)
when "float", "F" then (puts("Enter a float") || gets.to_f)
end
}
Jusqu'à présent, j'ai créé du code qui fonctionnait en utilisant une boucle for, mais je voulais savoir s'il y avait un moyen de l'optimiser et d'avoir le moins de lignes de code.
Dans Ruby, les retours à la ligne ne sont jamais nécessaires, donc "le moins de lignes de code" pour tout problème dans Ruby est toujours 1:
puts "how many elements?"; max = gets.to_i; array = []; for i in 0..max - 1 do puts "are you entering in a string, an int or a float?"; data_type = gets.chomp; if %W[string STRING String s S].include?(data_type) then puts "enter in a string"; array[i] = gets.chomp elsif %W[int INT Int i I].include?(data_type) then puts "enter an int"; array[i] = gets.to_i elsif %W[Float FLOAT float f F].include?(data_type) then puts "enter a float"; array[i] = gets.to_f end end; print array
Votre critère est quelque chose que l'on voit normalement sur Code Golf .