ruby-on-rails-ruby,如何使用相同的键添加来自两个哈希的值,而不覆盖这些值?

uwopmtnx  于 2021-09-29  发布在  Java
关注(0)|答案(3)|浏览(215)

首先,感谢您在这一点上帮助我回答sql问题。
现在我正在为另一件事而挣扎,这让我想到,老实说,我是否应该放弃做程序员。
无论如何,我的问题是:我有一个散列数组(在该散列中还有一个散列),如下所示:

[
 {"A1"=>{:month=>1.0, :balance=>"0.0000", :price=>"9.0000"}}, 
 {"A1"=>{:month=>7.0, :balance=>"34030.0000", :price=>"34030.0000"}},
 {"A3"=>{:month=>4.0, :balance=>"34030.0000", :price=>"34030.0000"}},
 ...
]

我试图实现的是,如果有两个值具有相同的键,即“a1”将这些值添加到一个完整的散列中,而不会覆盖旧值,也不会将月份作为所需的键输出:

[
 {"A1"=> { 1 => { :balance=> "0.0000", :price=>"9.0000"} },
         { 7 => { :balance => "34030.0000", :price => "34030.0000" } }},
  and so on... 
]

这可能吗?

xkrw2x1b

xkrw2x1b1#

由于数据的当前格式,您需要的不仅仅是几次转换。它们中的大多数都基于转换结果散列的值,在按其唯一键对数组中的散列进行分组之后:

data
  .group_by { |hash| hash.keys.first }                                     # (1)
  .transform_values { |value| value.flat_map(&:values) }                   # (2)
  .transform_values { |values| values.index_by { |value| value[:month] } } # (3)

第一种转换是通过当前对象的唯一散列键对当前对象进行分组,该对象包含一个散列数组,因此 keys.first ,导致:

{
  "A1"=>[
    {"A1"=>{:month=>1.0, :balance=>"0.0000", :price=>"9.0000"}}, 
    {"A1"=>{:month=>7.0, :balance=>"34030.0000", :price=>"34030.0000"}}
  ],
  "A3"=>[{"A3"=>{:month=>4.0, :balance=>"34030.0000", :price=>"34030.0000"}}]
}

第二种方法是使用哈希数组仅从结果哈希中的每个哈希中提取值:

{
  "A1"=>[
    {:month=>1.0, :balance=>"0.0000", :price=>"9.0000"}, 
    {:month=>7.0, :balance=>"34030.0000", :price=>"34030.0000"}
  ],
  "A3"=>[{:month=>4.0, :balance=>"34030.0000", :price=>"34030.0000"}]
}

然后,它只是缺少将散列数组转换为简单的散列,其键是 month :

{
  "A1"=>{
    1.0=>{:month=>1.0, :balance=>"0.0000", :price=>"9.0000"}, 
    7.0=>{:month=>7.0, :balance=>"34030.0000", :price=>"34030.0000"}
  },
  "A3"=>{4.0=>{:month=>4.0, :balance=>"34030.0000", :price=>"34030.0000"}}
}
nszi6y05

nszi6y052#

@塞巴斯蒂安的回答很好。对于多样性,我们也考虑一种迭代方法。不确定它是更有效还是更容易理解,但理解多个视角总是好的。
设置您提供给我们的输入数据:

arr = [
 {"A1"=>{:month=>1.0, :balance=>"0.0000", :price=>"9.0000"}}, 
 {"A1"=>{:month=>7.0, :balance=>"34030.0000", :price=>"34030.0000"}},
 {"A3"=>{:month=>4.0, :balance=>"34030.0000", :price=>"34030.0000"}}]

我们为结果创建一个新的空哈希。

new_hash = {}

现在迭代原始数据。我们将对数据的形式做一些假设。


# We know each thing is going to be a hash.

arr.each do |hsh|
    # Set up some convenient variables for keys and 
    # values we'll need later.
    key = hsh.keys.first
    value = hsh.values.first
    month = value[:month]

    # If the output hash doesn't yet have the key,
    # give it the key and assign an empty hash to it.
    new_hash[key] ||= {}
    # Assign the value to the hash, keyed to the current month.
    new_hash[key][month] = value
    # ... and get rid of the month key that's now redundant.
    new_hash[key][month].delete(:month)
end

结果是:

{"A1"=>{1.0=>{:balance=>"0.0000", :price=>"9.0000"}, 
        7.0=>{:balance=>"34030.0000", :price=>"34030.0000"}}, 
 "A3"=>{4.0=>{:balance=>"34030.0000", :price=>"34030.0000"}}}
nfg76nw0

nfg76nw03#

可以说,将所需的返回值设置为散列更有用:

h = {"A1"=>{1=>{:balance=>    "0.0000", :price=>    "9.0000"},
            7=>{:balance=>"34030.0000", :price=>"34030.0000"}},
     "A3"=>{4=>{:balance=>"34030.0000", :price=>"34030.0000"}}}

你可以这样写,例如:

require 'bigdecimal'

BigDecimal(h['A1'][7][:price]) 
  #=> 0.3403e5

参见bigdecimal。 BigDecimal 通常用于财务计算,因为它避免了舍入误差。
此结果可通过更改 :month 到整数 arr :

arr = [
  {"A1"=>{:month=>1, :balance=>    "0.0000", :price=>    "9.0000"}}, 
  {"A1"=>{:month=>7, :balance=>"34030.0000", :price=>"34030.0000"}},
  {"A3"=>{:month=>4, :balance=>"34030.0000", :price=>"34030.0000"}}
]

通过计算:

h = arr.each_with_object({}) do |g,h|
  k,v = g.flatten
  (h[k] ||= {}).update(v[:month]=>v.reject { |k,_| k == :month })
end

参见散列#展平、散列#更新(又名 merge! )和hash#拒绝。
人们也可以这样写:

h = arr.each_with_object(Hash.new { |h,k| h[k] = {} }) do |g,h|
  k,v = g.flatten
  h[k].update(v[:month]=>v.reject { |k,_| k == :month })
end

请参阅接受块的hash::new的形式。

相关问题