我有以下 item.json 文件
{
"items": [
{
"brand": "LEGO",
"stock": 55,
"full-price": "22.99",
},
{
"brand": "Nano Blocks",
"stock": 12,
"full-price": "49.99",
},
{
"brand": "LEGO",
"stock": 5,
"full-price": "199.99",
}
]
}
有两个名为LEGO的项目,我想获得个别品牌的总库存量的输出。
在ruby文件 item.rb 中,我的代码如下:
require 'json'
path = File.join(File.dirname(__FILE__), '../data/products.json')
file = File.read(path)
products_hash = JSON.parse(file)
products_hash["items"].each do |brand|
puts "Stock no: #{brand["stock"]}"
end
我为每个品牌单独输出了库存,我需要将两个品牌名称“LEGO”的库存汇总为一个。 有人有解决方案吗?
答案 0 :(得分:1)
json = File.open(path,'r:utf-8',&:read) # in case the JSON uses UTF-8
items = JSON.parse(json)['items']
stock_by_brand = items
.group_by{ |h| h['brand'] }
.map do |brand,array|
[ brand,
array
.map{ |item| item['stock'] }
.inject(:+) ]
end
.to_h
#=> {"LEGO"=>60, "Nano Blocks"=>12}
它的工作原理如下:
Enumerable#group_by
获取项目数组并创建哈希,将品牌名称映射到具有该品牌的所有item
哈希数组Enumerable#map
将该哈希中的每个品牌/数组对转换为品牌数组(未更改),然后执行以下操作:
Enumerable#map
仅选择"stock"
计数,然后Enumerable#inject
将所有这些加在一起Array#to_h
然后将该两个值数组的数组转换为哈希值,将品牌映射到stock
值的总和。 如果您想要更简单的代码 functional 并且可能更容易理解:
stock_by_brand = {} # an empty hash
items.each do |item|
stock_by_brand[ item['brand'] ] ||= 0 # initialize to zero if unset
stock_by_brand[ item['brand'] ] += item['stock']
end
p stock_by_brand #=> {"LEGO"=>60, "Nano Blocks"=>12}
答案 1 :(得分:1)
要查看您的JSON字符串的外观,请使用您的哈希创建它,我已将其表示为h
:
require 'json'
j = JSON.generate(h)
#=> "{\"items\":[{\"brand\":\"LEGO\",\"stock\":55,\"full-price\":\"22.99\"},{\"brand\":\"Nano Blocks\",\"stock\":12,\"full-price\":\"49.99\"},{\"brand\":\"LEGO\",\"stock\":5,\"full-price\":\"199.99\"}]}"
从文件读取变量j
之后,我们现在可以解析它以获取"items"
的值:
arr = JSON.parse(j)["items"]
#=> [{"brand"=>"LEGO", "stock"=>55, "full-price"=>"22.99"},
# {"brand"=>"Nano Blocks", "stock"=>12, "full-price"=>"49.99"},
# {"brand"=>"LEGO", "stock"=>5, "full-price"=>"199.99"}]
获得所需结果的一种方法是使用计数哈希:
arr.each_with_object(Hash.new(0)) {|g,h| h.update(g["brand"]=>h[g["brand"]]+g["stock"])}
#=> {"LEGO"=>60, "Nano Blocks"=>12}
Hash.new(0)
创建一个空哈希(由块变量h
表示),默认值为零 1 。这意味着如果哈希没有键h[k]
,k
将返回零。
对于arr
的第一个元素(由块变量g
表示),我们有:
g["brand"] #=> "LEGO"
g["stock"] #=> 55
因此,在该区块中,计算为:
g["brand"] => h[g["brand"]]+g["stock"]
#=> "LEGO" => h["LEGO"] + 55
最初h
没有密钥,因此h["LEGO"]
会返回默认值零,从而导致{ "LEGO"=>55 }
合并到哈希h
中。由于h
现在有一个键"LEGO"
,h["LEGO"]
,在后续计算中不会返回默认值。
另一种方法是使用Hash#update(aka merge!
)的形式,它使用一个块来确定合并的两个哈希中存在的键的值:
arr.each_with_object({}) {|g,h| h.update(g["brand"]=>g["stock"]) {|_,o,n| o+n}}
#=> {"LEGO"=>60, "Nano Blocks"=>12}
1 k=>v
是{ k=>v }
作为方法论证时的简写。