循环使用红宝石的哈希值



我有:

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

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

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

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}

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

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"] 

步骤 1:创建默认值为零的空哈希

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

对于哈希h的默认值为0意味着如果h没有键kh[k]将返回0。在这里我们将编写h[k] += 1,它扩展到

h[k] = h[k] + 1

如果(在执行此表达式之前)h右侧没有键kh[k]返回零,因此我们有

h[k] = 0 + 1
#=> 1

此后,右侧的h[k]将为正整数。

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

h.[]=(h.[](k) + 1)

左边是方法[]=,右边是方法[]。当h没有键k时返回默认值是h.[](k)

找到一个 Hash 方法m(实际上不是"m")来执行此操作。

h = Hash.m(?)

问号表示必须为方法m提供参数。

步骤 2:单步执行blockchain中的哈希以更新哈希h

blockchain.each do |g|
h[?] += ?
h[?] -= ? unless ? == nil
end
h #=> {"brian"=>8000, "ben"=>10350, "jeff"=>2650}

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

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

blockchain.each_with_object(Hash.m(?)) do |g,h|
h[?] += ??
h[?] -= ?? unless ?? == nil
end
#=> {"brian"=>8000, "ben"=>10350, "jeff"=>2650}

在这里,???分别是参数和表达式的占位符。

Amogh Hegde的真棒答案,但不知何故,它不适用于我的Ruby 2.5.1系统,但是如果您在顶部脚本上添加require 'active_support/all',它将起作用。但我试图在不包括任何东西的情况下做到这一点。所以做了非常小的改变。以下是我刚刚更改的完整代码,如果检查:from_user的条件是否存在,所以我已转换为字符串,然后使用 empty 方法对其进行检查。

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}

在一次迭代中:

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}

最新更新