Ruby哈希数组单个键遍历方法及食谱份数转换器代码报错求助
Hey there! Let's work through your recipe converter problems step by step—first optimizing your input code, then fixing that portion conversion error, and finally clarifying how to work with your array of hashes in Ruby.
1. Optimizing the Ingredient Input Code
Your current input code works, but we can make it cleaner, more robust, and ready for the math later on. Here are the key improvements:
- Remove unused defaults: Your
quantity = 1,metric = "g", andingredient = "default"aren't actually used since you overwrite them with user input. - Convert quantity to a number: Right now you're storing quantity as a string, which will break math operations later. We'll convert it to a
Float(to handle fractions like 2.5) orInteger. - Simplify loop logic: Make prompts clearer and avoid repeating the "press X" instruction.
- Add basic input validation: Ensure the user enters a valid number for quantity.
- Simplify ingredient creation: You don't need a separate method—you can create the hash directly when pushing to the array.
Here's the optimized version:
puts "Please enter your recipe ingredients. Press X when done.\n" recipe = [] loop do puts "Enter ingredient name (or X to finish):" ingredient = gets.chomp.capitalize break if ingredient == "X" puts "Enter unit (e.g., g, oz, cup):" metric = gets.chomp.downcase # Validate quantity input quantity = nil until quantity puts "Enter quantity (e.g., 500, 2.5):" input = gets.chomp # Try converting to float first, fall back to integer quantity = Float(input) rescue Integer(input) rescue nil puts "Please enter a valid number!" unless quantity end recipe << { quantity: quantity, metric: metric, ingredient: ingredient } end puts "\nYour recipe ingredients:" recipe.each { |ing| puts "#{ing[:quantity]} #{ing[:metric]} #{ing[:ingredient]}" }
2. Fixing the Portion Conversion Error
The main error you're seeing (undefined local variable or method orig_portion'`) happens because Ruby methods have their own scope—they can't access variables defined in the main program unless you pass them as arguments. Let's fix this, plus other syntax and logic issues:
First, Fix the Portion Input Code
Your current portion input has syntax errors (extra end statements) and incorrect validation. Here's the corrected version:
# Get original portion size with validation orig_portion = nil until orig_portion puts "\nHow many portions is this recipe for?" input = gets.chomp orig_portion = Integer(input) rescue nil puts "Please enter a valid whole number!" unless orig_portion end # Get new portion size with validation new_portion = nil until new_portion puts "How many people are you cooking for?" input = gets.chomp new_portion = Integer(input) rescue nil puts "Please enter a valid whole number!" unless new_portion end
Then, Fix the convert_recipe Method
We need to pass orig_portion and new_portion as arguments to the method. Also, your loop was trying to iterate over key, value (which is for hashes), but recipe is an array of hashes—so we iterate over each hash in the array instead. Finally, use the correct symbol keys to access hash values:
def convert_recipe(recipe, orig_portion, new_portion) conversion_factor = new_portion.to_f / orig_portion.to_f recipe.each do |ingredient_hash| updated_quantity = ingredient_hash[:quantity] * conversion_factor # Round to 2 decimal places for readability (adjust as needed) rounded_quantity = sprintf("%.2f", updated_quantity).to_f # Remove .0 if it's a whole number rounded_quantity = rounded_quantity.to_i if rounded_quantity == rounded_quantity.to_i puts "#{rounded_quantity} #{ingredient_hash[:metric]} #{ingredient_hash[:ingredient]}" end end # Run the conversion puts "\nConverted recipe for #{new_portion} portions:" convert_recipe(recipe, orig_portion, new_portion)
3. How to Iterate Over an Array of Hashes in Ruby
To clarify: Your recipe variable is an array where each element is a hash. When you loop through it:
- Use
recipe.each do |ingredient_hash|to grab each individual hash from the array. - Access values inside the hash using the symbol keys you defined (e.g.,
ingredient_hash[:quantity],ingredient_hash[:metric]).
For example, if you just wanted to print all ingredient names:
recipe.each do |ing| puts ing[:ingredient] end
If you wanted to collect all quantities into a separate array:
quantities = recipe.map { |ing| ing[:quantity] } puts quantities.inspect
Putting It All Together
Combine the optimized input code, portion input code, and conversion method, and your recipe converter will work smoothly—handling input validation, correct type conversions, and portion scaling without errors.
内容的提问来源于stack exchange,提问作者Siobhan Vida Ashmole

