更新时间:2021-12-09 02:39:47
这样做的一种方法是使用哈希#更新(又名合并!
),使用块来确定的值这是两个散列值present键被合并。
One way of doing this is to use the form of Hash#update (aka merge!
) that uses a block to determine the values of keys that are present in both hashes being merged.
code
def f_addition(arr, group_fields, sum_fields, max_fields)
arr.each_with_object({}) do |h,g|
g.update( h.values_at(*group_fields) => h ) do |_,gv,hv|
gv.merge(hv) do |k,gvv,hvv|
case
when sum_fields.include?(k) then "%.2f" % (gvv.to_f + hvv.to_f)
when max_fields.include?(k) then [gvv, hvv].max
else gvv
end
end
end
end.values
end
示例
arr = [{ "id"=>2, "idx"=>111, "money"=>"4.00", "money1"=>"1.00",
"order"=>"001", "order1"=>"1", "pet"=>"dog" },
{ "id"=>1, "idx"=>112, "money"=>"2.00", "money1"=>"2.00",
"order"=>"001", "order1"=>"1", "sport"=>"darts" },
{ "id"=>3, "idx"=>113, "money"=>"3.00", "money1"=>"1.00",
"order"=>"002", "order1"=>"2" }]
请注意,此数组是从问题中给出的略有不同。我已经加入宠儿=>中的狗
来的第一个(散)元素运动=>中镖
和第二哈希值。
Notice that the this array is slightly different from from the one given in the question. I have added "pet"=>"dog"
to the first (hash) element "sport"=>"darts"
and to the second hash.
f_addition(arr, ["order","order1"], ["money","money1"], ["id", "idx"] )
#=> [{ "id"=>2, "idx"=>112, "money"=>"6.00", "money1"=>"3.00",
# "order"=>"001", "order1"=>"1", "pet"=>"dog", "sport"=>"darts"},
# { "id"=>3, "idx"=>113, "money"=>"3.00", "money1"=>"1.00",
# "order"=>"002", "order1"=>"2" }]
说明
有关上面的例子:
group_fields = ["order", "order1"]
sum_fields = ["money", "money1"]
max_fields = ["id", "idx"]
enum = arr.each_with_object({})
#=> #<Enumerator: [{"id"=>2, "idx"=>111,..., "pet"=>"dog"},
# {"id"=>1, "idx"=>112,..., "sport"=>"darts"},
# {"id"=>3,"idx"=>113,...,"order1"=>"2"}]:each_with_object({})>
阵列#每个每个传递此枚举成块元素,并将其分配给块变量。传递的第一个元素是:
Array#each passes each element of this enumerator into the block and assigns it to the block variables. The first element passed is:
h, g = enum.next
#=> [{ "id"=>2, "idx"=>111, "money"=>"4.00", "money1"=>"1.00",
"order"=>"001", "order1"=>"1", "pet"=>"dog" }, {}]
h #=> { "id"=>2, "idx"=>111, "money"=>"4.00", "money1"=>"1.00",
"order"=>"001", "order1"=>"1", "pet"=>"dog" }
g #=> {}
为:
h.values_at(*group_fields)
#=> h.values_at(*["order", "order1"])
#=> h.values_at("order", "order1")
#=> ["001", "1"]
我们计算:
g.update(["001", "1"] => h) do |k,gv,hv| ... end
这是简写:
g.update({ ["001", "1"] => h }) do |k,gv,hv| ... end
块做| K,GV,HV | ...结束
只用时要合并的两个散列都包含键 K
。 1 如 G = {}
不包含任何键,该块不会在这个时候使用的:
The block do |k,gv,hv| ... end
is only used when the two hashes being merged both contain the key k
.1 As g = {}
contains no keys, the block is not used at this time:
g.update({ ["001", "1"] => h })
#=> {}.update({ ["001", "1"]=>{ "id"=>2, "idx"=>111, "money"=>"4.00",
# "money1"=>"1.00", "order"=>"001",
# "order1"=>"1", "pet"=>"dog" } }
#=> { ["001", "1"]=>{ "id"=>2, "idx"=>111, "money"=>"4.00", "money1"=>"1.00",
# "order"=>"001", "order1"=>"1", "pet"=>"dog" } }
在由更新
返回的值是新值先按g
。
枚举
传递到块的下一个值是:
The next value of enum
passed into the block is:
h, g = enum.next
h #=> { "id"=>1, "idx"=>112, "money"=>"2.00", "money1"=>"2.00",
# "order"=>"001", "order1"=>"1", "sport"=>"darts" },
g #=> { ["001", "1"]=>{ "id"=>2, "idx"=>111, "money"=>"4.00", "money1"=>"1.00",
# "order"=>"001", "order1"=>"1", "pet"=>"dog" } }]
为:
h.values_at(*group_fields)
#=> h.values_at("order", "order1")
#=> ["001", "1"]
我们计算:
g.update(["001", "1"] => h) do |k,gv,hv| ... end
由于先按g
和 {[001,1] =&GT; h}可以
都包含键[001,1],我们必须按照块,以确定在合并后的哈希键的值。我们有:
As g
and { ["001", "1"] => h }
both contain the key ["001", "1"], we must defer to the block to determine the value of that key in the merged hash. We have:
k = ["001", "1"]
gv = { "id"=>2, "idx"=>111, "money"=>"4.00", "money1"=>"1.00",
"order"=>"001", "order1"=>"1", "pet"=>"dog" }
hv = { "id"=>1, "idx"=>112, "money"=>"2.00", "money1"=>"2.00",
"order"=>"001", "order1"=>"1", "sport"=>"darts" }
我们因此如下评价块(使用合并
,而不是合并/更新
!):
We therefore evaluate the block as follows (using merge
rather than merge!/update
):
gv.merge(hv) do |k,gvv,hvv|
case
when sum_fields.include?(k) then "%.2f" % (gvv.to_f + hvv.to_f)
when max_fields.include?(k) then [gvv, hvv].max
else gvv
end
end
#=> { "id"=>2, "idx"=>112, "money"=>"6.00", "money1"=>"3.00",
# "order"=>"001", "order1"=>"1", "pet"=>"dog", "sport"=>"darts"}
GV
不包含关键的运动,因此合并运动=&GT当不使用块,飞镖
到 GV
。 HVV
的所有其他键都在 GVV present
,不过,所以我们使用的块,以确定它们的值在合并后的哈希值。适用于:
gv
does not contain the key "sport", so the block is not used when merging "sport"=>"darts"
into gv
. All other keys of hvv
are present in gvv
, however, so we use the block to determine their values in the merged hash. For:
k = "money"
gvv = "4.00"
hvv = "2.00"
我们发现:
sum_fields.include?(k)
#=> ["money", "money1"].include?("money")
#=> true
所以情况
语句返回:
"%.2f" % (gvv.to_f + hvv.to_f)
#=> "%.2f" % ("4.00".to_f + "2.00".to_f)
#=> "6.00"
为高压
的其他键的值,散列合并到 GV
,也同样计算,给予我们合并后的散列的新值先按g
。
The values for other keys of hv
, the hash being merged into gv
, are computed similarly, to give us a new value for the merged hash g
.
最后,
{ ["002", "order1"] => { "id"=>3, "idx"=>113, "money"=>"3.00",
"money1"=>"1.00", "order"=>"002", "order1"=>"2" }]
合并到先按g
(不要求使用的块更新
)和 g.values
是由该方法返回。
is merged into g
(which does not require the use update
's block) and g.values
is returned by the method.
观察
这将是易于推广这种通过对,如:
It would be easy to generalize this to pass pairs such as:
[["money","money1"], ->(a,b) { "%.2f" % (a.to_f + b.to_f) }]
[["id", "idx"], :max]
这可以做如下:
def f_addition(arr, group_fields, *mods)
arr.each_with_object({}) do |h,g|
g.update( h.values_at(*group_fields) => h ) do |_,gv,hv|
gv.merge(hv) do |k,gvv,hvv|
f,op = mods.find { |f,op| f.include?(k) }
if f
case op
when Proc then op.call(gvv,hvv)
when Symbol then [gvv, hvv].send(op)
end
else
gvv
end
end
end
end.values
end
f_addition(arr, ["order","order1"],
[["money","money1"], ->(a,b) { "%.2f" % (a.to_f + b.to_f) }],
[["id", "idx"], :max])
# => [{ "id"=>2, "idx"=>112, "money"=>"6.00", "money1"=>"3.00",
# "order"=>"001", "order1"=>"1", "pet"=>"dog", "sport"=>"darts" },
# { "id"=>3, "idx"=>113, "money"=>"3.00", "money1"=>"1.00",
# "order"=>"002", "order1"=>"2" }]
1. We will find that the calculations in the block do not depend on the block variable `k`.
I've therefore replaced that variable with the local variable _, to so-inform the reader.