循环哈希为红宝石

时间:2019-02-15 01:16:55

标签: ruby

我有:

blockchain = [
  { from_user: nil, to_user: "brian", amount: 21000 },
  { from_user: "brian", to_user: "ben", amount: 9000 },
  { from_user: "brian", to_user: "jeff", amount: 7000 },
  { from_user: "ben", to_user: "jeff", amount: 400 },
  { from_user: "brian", to_user: "jeff", amount: 1500 },
  { from_user: "jeff", to_user: "brian", amount: 4500 },
  { from_user: "jeff", to_user: "ben", amount: 1750 }
]

我想获得每个人的最终金额,总计,但剩余硬币。它应该打印出来:

Brian's balance is 8000
Ben's balance is 10350
Jeff's balance is 2650

我试图弄清楚如何编写代码。有人可以帮忙吗?

5 个答案:

答案 0 :(得分:1)

步骤1:创建一个默认值为零的空散列

此哈希的键将是用户,其值将是每个用户在任何给定时间所拥有的数量。

让哈希h的默认值为0意味着如果h[k]没有密钥{{1},0返回h }。在这里,我们将编写k,它扩展为

h[k] += 1

如果(在执行此表达式之前)h[k] = h[k] + 1 没有右侧的键h k返回零,那么我们有

h[k]

此后,右侧的h[k] = 0 + 1 #=> 1 将为正整数。

如果您想知道为什么表达式左侧的h[k]不返回h[k],请记住0是实际表达式的语法糖

h[k] = h[k] + 1

我们在左侧有方法h.[]=(h.[](k) + 1) ,在右侧有方法[]=。当[]没有密钥h.[](k)时,是h返回默认值。

找到一种Hash方法k(实际上不是“ m”)来做到这一点。

m

问号意味着您必须为方法h = Hash.m(?) 提供一个参数。

步骤2:逐步浏览m中的哈希值以更新哈希值blockchain

h

我们现在拥有打印所需结果所需的信息。

在实践中,我们将使用方法Enumerable#each_with_object链接这两个步骤:

blockchain.each do |g|
  h[?] += ?
  h[?] -= ? unless ? == nil
end

h #=> {"brian"=>8000, "ben"=>10350, "jeff"=>2650}

此处blockchain.each_with_object(Hash.m(?)) do |g,h| h[?] += ?? h[?] -= ?? unless ?? == nil end #=> {"brian"=>8000, "ben"=>10350, "jeff"=>2650} ?分别是参数和表达式的占位符。

答案 1 :(得分:1)

您可以通过以下方式进行操作:

blockchain = [
  { from_user: nil, to_user: "brian", amount: 21000 },
  { from_user: "brian", to_user: "ben", amount: 9000 },
  { from_user: "brian", to_user: "jeff", amount: 7000 },
  { from_user: "ben", to_user: "jeff", amount: 400 },
  { from_user: "brian", to_user: "jeff", amount: 1500 },
  { from_user: "jeff", to_user: "brian", amount: 4500 },
  { from_user: "jeff", to_user: "ben", amount: 1750 }
]

users = {}

blockchain.each do |block|
    users[block[:from_user]] = 0 if !users.keys.include?(block[:from_user]) && block[:from_user].present?
    users[block[:to_user]] = 0 if !users.keys.include?(block[:to_user])

    users[block[:to_user]] = users[block[:to_user]] + block[:amount]
    users[block[:from_user]] = users[block[:from_user]] - block[:amount] if block[:from_user].present?
end

puts users

users哈希将包含您所需的输出

{"brian"=>8000, "ben"=>10350, "jeff"=>2650}

答案 2 :(得分:1)

下面是简单实施,以实现每个人的平衡,

add = blockchain.group_by { |x| x[:to_user] }.reject { |k,v| k.nil? }.transform_values { |v| v.map { |x| x[:amount] }.sum }
# => {"brian"=>25500, "ben"=>10750, "jeff"=>8900}
sub = blockchain.group_by { |x| x[:from_user] }.reject { |k,v| k.nil? }.transform_values { |v| v.map { |x| x[:amount] }.sum }
# => {"brian"=>17500, "ben"=>400, "jeff"=>6250}

people = (add.keys + sub.keys).uniq
# => ["brian", "ben", "jeff"]

people.each { |x| puts "#{x.capitalize}'s balance is #{add[x].to_i - sub[x].to_i}" }

# Brian's balance is 8000
# Ben's balance is 10350
# Jeff's balance is 2650
# => ["brian", "ben", "jeff"] 

答案 3 :(得分:0)

Amogh Hegde的出色回答,但不知何故,它在我的系统上不支持ruby 2.5.1,但是如果您在顶部脚本中添加require 'active_support/all',它将起作用。但是我尝试不添加任何东西。因此做了很小的改动。以下是我是否更改了:from_user条件的情况下刚刚更改的完整代码,因此我已转换为字符串,然后使用空方法进行了检查。

blockchain = [
  { from_user: nil, to_user: "brian", amount: 21000 },
  { from_user: "brian", to_user: "ben", amount: 9000 },
  { from_user: "brian", to_user: "jeff", amount: 7000 },
  { from_user: "ben", to_user: "jeff", amount: 400 },
  { from_user: "brian", to_user: "jeff", amount: 1500 },
  { from_user: "jeff", to_user: "brian", amount: 4500 },
  { from_user: "jeff", to_user: "ben", amount: 1750 }
]

users = {}

blockchain.each do |block|
    users[block[:from_user]] = 0 if !users.keys.include?(block[:from_user]) && !block[:from_user].to_s.empty?
    users[block[:to_user]] = 0 if !users.keys.include?(block[:to_user])
    users[block[:to_user]] = users[block[:to_user]] + block[:amount]
    users[block[:from_user]] = (users[block[:from_user]] - block[:amount]) if !block[:from_user].to_s.empty?
end

puts users

我得到以下回应。

{"brian"=>8000, "ben"=>10350, "jeff"=>2650}

答案 4 :(得分:0)

一次迭代:

blockchain.each_with_object(Hash.new(0)) do |h, nh|
  nh[h[:from_user]] -= h[:amount]
  nh[h[:to_user]] += h[:amount]
end

#=> {nil=>-21000, "brian"=>8000, "ben"=>10350, "jeff"=>2650}


要跟踪完整的运动,请执行以下操作:

blockchain.each_with_object(Hash.new { |h,k| h[k] = Hash.new(0) }) do |h, nh|
  nh[h[:from_user]][:out] -= h[:amount]
  nh[h[:to_user]][:in] += h[:amount]
end


#=> {nil=>{:out=>-21000}, "brian"=>{:in=>25500, :out=>-17500}, "ben"=>{:in=>10750, :out=>-400}, "jeff"=>{:in=>8900, :out=>-6250}}


其他选项:可以使用Enumerable#group_byHash#transform_values计算收入和结果,然后合并在一起。

收入是:

incomes = blockchain.group_by { |k,v| k[:to_user] }.transform_values{ |a| a.sum { |h| h[:amount] }}
#=> {"brian"=>25500, "ben"=>10750, "jeff"=>8900}

结果为(负):

outcomes = blockchain.group_by { |k,v| k[:from_user] }.transform_values{ |a| -a.sum { |h| h[:amount]}}
#=> {nil=>-21000, "brian"=>-17500, "ben"=>-400, "jeff"=>-6250}

然后合并,使用Hash#merge传递一个块:

incomes.merge(outcomes) { |k, income, outcome| income + outcome }
#=> {"brian"=>8000, "ben"=>10350, "jeff"=>2650, nil=>-21000}