0

我目前正在学习 Ruby,并且正在尝试编写一个简单的 Rubygrocery_list方法。以下是说明:

我们想编写一个程序来帮助跟踪购物清单。它将杂货项目(如“鸡蛋”)作为参数,并返回杂货清单(即项目名称和每个项目的数量)。如果你两次传递相同的参数,它应该增加数量。

def grocery_list(item)
  array = []
  quantity = 1
  array.each {|x| quantity += x }
  array << "#{quantity}" + " #{item}"
end

puts grocery_list("eggs", "eggs") 

所以我想在这里弄清楚如何通过两次传递鸡蛋来返回“2个鸡蛋”

4

5 回答 5

4

为了帮助您计算可以用作哈希的不同项目。哈希类似于数组,但使用字符串而不是整数作为索引:

a = Array.new
a[0] = "this"
a[1] = "that"

h = Hash.new
h["sonja"] = "asecret"
h["brad"] = "beer"

在此示例中,哈希可能用于存储用户的密码。但是对于您的示例,您需要一个哈希来计数。调用grocery_list("eggs", "beer", "milk", "eggs") 应该会导致执行以下命令:

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!,它在字符串末尾“切掉”一个字符:

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 
于 2013-05-04T21:59:28.643 回答
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方法使用它来构建一个字符串数组,该数组连接到一个逗号分隔的字符串。

于 2013-05-04T23:48:19.300 回答
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
于 2013-05-04T21:44:38.413 回答
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}
于 2013-05-04T21:03:17.637 回答
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
于 2013-05-04T22:19:03.330 回答