我目前正在学习Ruby,而我正在尝试编写一个简单的Ruby grocery_list
方法。以下是说明:
我们想写一个程序来帮助跟踪购物清单。它将杂货项目(如“鸡蛋”)作为参数,并返回购物清单(即每个项目的数量的项目名称)。如果你传递两次相同的参数,它应该增加数量。
def grocery_list(item)
array = []
quantity = 1
array.each {|x| quantity += x }
array << "#{quantity}" + " #{item}"
end
puts grocery_list("eggs", "eggs")
所以我试图弄清楚如何通过传两次鸡蛋来回归“2个鸡蛋”
答案 0 :(得分:4)
帮助您计算可用作哈希的不同项目。 Hash类似于Array,但是使用Strings而不是Integers als a Index:
a = Array.new
a[0] = "this"
a[1] = "that"
h = Hash.new
h["sonja"] = "asecret"
h["brad"] = "beer"
在此示例中,Hash可能用于存储用户的密码。但对你而言 例如,您需要哈希计数。叫杂货店名单(“鸡蛋”,“啤酒”,“牛奶”,“鸡蛋”) 应该导致执行以下命令:
h = Hash.new(0) # empty hash {} created, 0 will be default value
h["eggs"] += 1 # h is now {"eggs"=>1}
h["beer"] += 1 # {"eggs"=>1, "beer"=>1}
h["milk"] += 1 # {"eggs"=>1, "beer"=>1, "milk"=>1}
h["eggs"] += 1 # {"eggs"=>2, "beer"=>1, "milk"=>1}
您可以使用每个循环处理Hash的所有键和值:
h.each{|key, value| .... }
并建立我们需要的字符串,添加 如果需要,项目数和项目名称。 在循环内部,我们总是在末尾添加一个逗号和一个空格。 最后一个元素不需要这样,所以在之后 循环完成我们留下了
"2 eggs, beer, milk, "
为了摆脱最后一个逗号和空白,我们可以使用chop !,“chops off” 字符串末尾的一个字符:
output.chop!.chop!
还需要做一件事来完成您的grocery_list的完整实现: 你指定应该像这样调用函数:
puts grocery_list("eggs", "beer", "milk","eggs")
所以grocery_list函数不知道它得到了多少个参数。我们可以处理 这通过在前面指定一个带有星号的参数,那么这个参数将会 是一个包含所有参数的数组:
def grocery_list(*items)
# items is an array
end
所以这就是:我为你做了功课并实施了grocery_list。 我希望你真的去理解实现的麻烦, 而且不要只是复制粘贴它。
def grocery_list(*items)
hash = Hash.new(0)
items.each {|x| hash[x] += 1}
output = ""
hash.each do |item,number|
if number > 1 then
output += "#{number} "
end
output += "#{item}, "
end
output.chop!.chop!
return output
end
puts grocery_list("eggs", "beer", "milk","eggs")
# output: 2 eggs, beer, milk
答案 1 :(得分:1)
def grocery_list(*item)
item.group_by{|i| i}
end
p grocery_list("eggs", "eggs","meat")
#=> {"eggs"=>["eggs", "eggs"], "meat"=>["meat"]}
def grocery_list(*item)
item.group_by{|i| i}.flat_map{|k,v| [k,v.length]}
end
p grocery_list("eggs", "eggs","meat")
#=>["eggs", 2, "meat", 1]
def grocery_list(*item)
Hash[*item.group_by{|i| i}.flat_map{|k,v| [k,v.length]}]
end
grocery_list("eggs", "eggs","meat")
#=> {"eggs"=>2, "meat"=>1}
grocery_list("eggs", "eggs","meat","apple","apple","apple")
#=> {"eggs"=>2, "meat"=>1, "apple"=>3}
或@Lee说:
def grocery_list(*item)
item.each_with_object(Hash.new(0)) {|a, h| h[a] += 1 }
end
grocery_list("eggs", "eggs","meat","apple","apple","apple")
#=> {"eggs"=>2, "meat"=>1, "apple"=>3}
答案 2 :(得分:1)
这是一个更详细,但也许更具可读性的解决方案来应对挑战。
def grocery_list(*items) # Notice the asterisk in front of items. It means "put all the arguments into an array called items"
my_grocery_hash = {} # Creates an empty hash
items.each do |item| # Loops over the argument array and passes each argument into the loop as item.
if my_grocery_hash[item].nil? # Returns true of the item is not a present key in the hash...
my_grocery_hash[item] = 1 # Adds the key and sets the value to 1.
else
my_grocery_hash[item] = my_grocery_hash[item] + 1 # Increments the value by one.
end
end
my_grocery_hash # Returns a hash object with the grocery name as the key and the number of occurences as the value.
end
这将创建一个空哈希(在其他语言中称为词典或地图),其中每个杂货店作为键添加,其值设置为1。如果同一个杂货店多次作为您方法的参数出现,则该值会递增。
如果你想创建一个文本字符串并返回而不是哈希对象,你可以在迭代后这样做:
grocery_list_string = "" # Creates an empty string
my_grocery_hash.each do |key, value| # Loops over the hash object and passes two local variables into the loop with the current entry. Key being the name of the grocery and value being the amount.
grocery_list_string << "#{value} units of #{key}\n" # Appends the grocery_list_string. Uses string interpolation, so #{value} becomes 3 and #{key} becomes eggs. The remaining \n is a newline character.
end
return grocery_list_string # Explicitly declares the return value. You can ommit return.
更新了评论的答案:
如果您在不添加哈希迭代的情况下使用第一种方法,则会返回一个哈希对象,可以用来查找这样的数量。
my_hash_with_grocery_count = grocery_list("Lemonade", "Milk", "Eggs", "Lemonade", "Lemonade")
my_hash_with_grocery_count["Milk"]
--> 1
my_hash_with_grocery_count["Lemonade"]
--> 3
答案 3 :(得分:1)
如果您想要轻松计算内容,可以使用哈希键来保存要计算的内容的名称,并且该键的值是数量。例如:
#!/usr/bin/env ruby
class GroceryList
attr_reader :list
def initialize
# Specify hash with default quantity of zero.
@list = Hash.new(0)
end
# Increment the quantity of each item in the @list, using the name of the item
# as a hash key.
def add_to_list(*items)
items.each { |item| @list[item] += 1 }
@list
end
end
if $0 == __FILE__
groceries = GroceryList.new
groceries.add_to_list('eggs', 'eggs')
puts 'Grocery list correctly contains 2 eggs.' if groceries.list['eggs'] == 2
end
答案 4 :(得分:1)
Enumerable#each_with_object
对于以下内容非常有用:
def list_to_hash(*items)
items.each_with_object(Hash.new(0)) { |item, list| list[item] += 1 }
end
def hash_to_grocery_list_string(hash)
hash.each_with_object([]) do |(item, number), result|
result << (number > 1 ? "#{number} #{item}" : item)
end.join(', ')
end
def grocery_list(*items)
hash_to_grocery_list_string(list_to_hash(*items))
end
p grocery_list('eggs', 'eggs', 'bread', 'milk', 'eggs')
# => "3 eggs, bread, milk"
它迭代数组或散列以便以方便的方式构建另一个对象。 list_to_hash
方法使用它从items数组构建一个哈希值(splat运算符将方法参数转换为数组);创建哈希,以便将每个值初始化为0. hash_to_grocery_list_string
方法使用它来构建一个字符串数组,该字符串连接到以逗号分隔的字符串。