Ruby杂货清单程序

时间:2013-05-04 20:55:14

标签: ruby

我目前正在学习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个鸡蛋”

5 个答案:

答案 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方法使用它来构建一个字符串数组,该字符串连接到以逗号分隔的字符串。