我的方法可以使用以下数据:
来自首次服务电话的数据:
date: 2015-04-01
my_array = [{Apple: 3}, {Banana: 2}, {Oranges: 4}]
来自第二次服务电话的数据:
date: 2015-04-05
my_array = [{Apple: 4}, {Banana: 5}, {Oranges: 1}, {Kiwi: 3}]
在方法结束时,我想返回一个哈希数组,它将从多个服务调用中收集数据。
逻辑应该检查密钥是否已经存在于散列中,如果是,则将值添加到现有密钥,如果不存在,则为该新密钥创建键值对象。对于此示例,第一次服务调用后的哈希值如下所示:
my_final_array = [{Apple: [2015-04-01, 3]}, {Banana: [2015-04-01, 2]}, {Oranges: [2015-04-01, 4]}]
然而,在我们从第二次服务调用中获取数据之后,我希望我的最终数组为:
my_final_array = [{Apple: [[2015-04-01, 3], [2015-04-05, 4]]}, {Banana: [[2015-04-01, 2], [2015-04-05, 5]]}, {Oranges: [[2015-04-01, 4], [2015-04-05, 1]]}, {Kiwi: [2015-04-05, 3]}]
有没有一种简单的方法可以得到我所期待的东西?
我所拥有的算法是迭代数据两次,即一旦我创建一个数组来从所有服务调用中收集数据,然后当我迭代数组以按键分组时。
这是我最初试图解决它的方式:
dates_array.each do |week_date|
my_array = #Collect data returned by service for each week_date.
my_array.each do |sample_data|
sample_array << [date, sample_data.keys.first, sample_data.values.first]
end
end
sample_hash = sample_array.each_with_object({}) { |data_value, key_name|
(key_name[data_value[1]] ||= []) << data_value.values_at(0,2)
}
#Convert sample_hash to my_final_array for third party input.
答案 0 :(得分:1)
当您有这些特定要求时,最好只创建自己的类 - 这样您就可以在内部存储数据,但这是最好的。例如
class FunkyThing
def initialize
@s = {}
end
def add date, arr
arr.each do |e|
k, v = e.flatten
( @s[k] ||= [] ) << [ date, v ]
end
end
def val
@s.map { |k, v| { k => v } }
end
end
那么:
[142] pry(main)> a = FunkyThing.new
=> #<FunkyThing:0x007fbc23ed5cb0 @s={}>
[143] pry(main)> a.add '2015-04-01', [{Apple: 3}, {Banana: 2}, {Oranges: 4}]
=> [{:Apple=>3}, {:Banana=>2}, {:Oranges=>4}]
[144] pry(main)> a.val
=> [{:Apple=>[["2015-04-01", 3]]}, {:Banana=>[["2015-04-01", 2]]}, {:Oranges=>[["2015-04-01", 4]]}]
[145] pry(main)> a.add '2015-04-05', [{Apple: 4}, {Banana: 5}, {Oranges: 1}, {Kiwi: 3}]
=> [{:Apple=>4}, {:Banana=>5}, {:Oranges=>1}, {:Kiwi=>3}]
[146] pry(main)> a.val
=> [{:Apple=>[["2015-04-01", 3], ["2015-04-05", 4]]}, {:Banana=>[["2015-04-01", 2], ["2015-04-05", 5]]}, {:Oranges=>[["2015-04-01", 4], ["2015-04-05", 1]]}, {:Kiwi=>[["2015-04-05", 3]]}]
[147] pry(main)>
请注意,第一个输出与您在问题中要求的输出不同,因为这些值已经嵌套在第二级,我想这可能是您想要的,所以我保持原样。
答案 1 :(得分:0)
像这样的东西,也许:
array_of_possible_keys.each do |key|
if my_final_hash.has_key?(key)
do something
else
do other thing
end
end
如果您要使用哈希值,则不必遍历数组。而且我没有看到任何不替换的原因
my_array = [{Apple: 4}, {Banana: 5}, {Oranges: 1}, {Kiwi: 3}]
my_final_array = [{Apple: [2015-04-01, 3]}, {Banana: [2015-04-01, 2]}, {Oranges: [2015-04-01, 4]}]
带
my_hash= {Apple: 4, Banana: 5, Oranges: 1, Kiwi: 3}
my_final_hash = {Apple: [2015-04-01, 3], Banana: [2015-04-01, 2], Oranges: [2015-04-01, 4]}
答案 2 :(得分:0)
这是一个接受当前版本的数组,日期和要处理的新数组的函数。
如果是第一次服务调用,则根据要处理的参数时间和数组创建一个新数组。对于后续服务调用,将根据数组的当前版本创建散列,然后处理参数(新)数组以向散列添加值。最后,哈希被转换回原始数组形式。
请参阅下面的示例代码:
<强>解决方案强>
def process_array(old_array: nil, date: date, my_array: my_array)
unless old_array
# service call # 1
my_array.each do |key_value_pair|
pair = key_value_pair.to_a.first
key = pair[0]
value = pair[1]
key_value_pair[key] = [date, value]
end
return my_array
else
# service call # 2 onwards
hash = {}
old_array.each do |key_value_pair|
pair = key_value_pair.to_a.first
key = pair[0]
value = pair[1]
hash[key] = value
end
my_array.each do |key_value_pair|
pair = key_value_pair.to_a.first
key = pair[0]
value = pair[1]
if hash.has_key?(key)
unless hash[key].first.kind_of?(Array)
hash[key] = [hash[key]]
end
hash[key] << [date, value]
else
hash[key] = [date, value]
end
end
output_array = []
hash.each do |key, value|
new_hash = {}
new_hash[key] = value
output_array << new_hash
end
output_array
end
end
<强>用法强>
service_1 = [{Apple: 3}, {Banana: 2}, {Oranges: 4}]
array_1 = process_array(old_array: nil, date: "2015-04-01", my_array: service_1)
puts array_1.to_s
# => [{:Apple=>["2015-04-01", 3]}, {:Banana=>["2015-04-01", 2]}, {:Oranges=>["2015-04-01", 4]}]
service_2 = [{Apple: 4}, {Banana: 5}, {Oranges: 1}, {Kiwi: 3}]
array_2 = process_array(old_array: array_1, date: "2015-04-05", my_array: service_2)
puts array_2.to_s
# => [{:Apple=>[["2015-04-01", 3], ["2015-04-05", 4]]}, {:Banana=>[["2015-04-01", 2], ["2015-04-05", 5]]}, {:Oranges=>[["2015-04-01", 4], ["2015-04-05", 1]]}, {:Kiwi=>["2015-04-05", 3]}]
答案 3 :(得分:0)
如果您要存储这样的数据:
data1 = [{ date: "2015-04-01",
my_array: [{Apple: 3}, {Banana: 2}, {Oranges: 4}] },
{ date: "2015-04-05",
my_array: [{Apple: 4}, {Banana: 5}, {Oranges: 1}, {Kiwi: 3}] }]
考虑将其更改为:
data2 = data1.map { |g|
{ date: g[:date],
my_hash: Hash[g[:my_array].flat_map(&:to_a)] }
}
#=> [{:date=>"2015-04-01",
# :my_hash=>{:Apple=>3, :Banana=>2, :Oranges=>4}},
# {:date=>"2015-04-05",
# :my_hash=>{:Apple=>4, :Banana=>5, :Oranges=>1, :Kiwi=>3}}]
我不知道这对你的目的是否会更好,但我希望你能看到它。然后,您可以按如下方式获得所需的分组:
result = data2.each_with_object({}) do |g,h|
g[:my_hash].each do |k,v|
h.update(k=>[g[:date],v]) do |_,o,n|
case o.first
when Array then o.concat(n)
else [o,n]
end
end
end
end
#=> {:Apple=> [["2015-04-01", 3], ["2015-04-05", 4]],
# :Banana=> [["2015-04-01", 2], ["2015-04-05", 5]],
# :Oranges=>[["2015-04-01", 4], ["2015-04-05", 1]],
# :Kiwi=> ["2015-04-05", 3]}
嗯,不,这不是你要求的,但是我希望你也能看到它,如果你发现它是一个更有用的数据结构。将此转换为您要求的内容很容易,我将在下面执行此操作,但首先,我想解释一些有关上述计算的内容。
result
的计算采用Hash#update(又名merge!
)的形式,该形式使用块来确定合并的两个哈希中存在的键的值。块变量为k,o,n
,其中:
k
是常用密钥(我已将其更改为_
以表示它未在块中使用); o
(对于“旧”)是k
中h
的值,正在构造的哈希值;和n
(对于“new”)是k
中g
的值,哈希被合并。 如果您希望上面:Kiwi
的值为[["2015-04-05", 3]]
(我认为在处理结果时会让生活更轻松),请将update
简化为:
h.update(k=>[[g[:date],v]]) { |_,o,n| o+n }
将result
转换为您要求的表单:
result.map { |k,a| { k=>a } }
#=> [{:Apple=> [["2015-04-01", 3], ["2015-04-05", 4]]},
# {:Banana=> [["2015-04-01", 2], ["2015-04-05", 5]]},
# {:Oranges=>[["2015-04-01", 4], ["2015-04-05", 1]]},
# {:Kiwi=>["2015-04-05", 3]}]