比较两个哈希数组并计算位置变化

时间:2018-02-27 17:35:44

标签: ruby

我正在尝试获取包含ID位置的两个哈希数组,并返回位置更改。数据来自不同日期的图表。

如果2018-01-01的图表1包含:

[
  {:position=>1, :id=>"GBMMV1800001"}, 
  {:position=>2, :id=>"GBMMV1800002"}, 
  {:position=>3, :id=>"GBMMV1800003"}
]

和2018-01-07的图表2包含:

[
  {:position=>1, :id=>"GBMMV1800001"}, 
  {:position=>2, :id=>"GBMMV1800003"},
  {:position=>3, :id=>"GBMMV1800002"}
]

如何生成显示位置变化的结果?

[
  {:position=>1, :id=>"GBMMV1800001", :change=>0}, 
  {:position=>2, :id=>"GBMMV1800003", :change=>1},
  {:position=>3, :id=>"GBMMV1800002", :change=>-1} 
]

5 个答案:

答案 0 :(得分:2)

假设没有重复的id s:

in1 = [
   {:position=>1, :id=>"GBMMV1800001"},   
   {:position=>2, :id=>"GBMMV1800002"},   
   {:position=>3, :id=>"GBMMV1800003"}  
]  
in2 = [
   {:position=>1, :id=>"GBMMV1800001"},   
   {:position=>2, :id=>"GBMMV1800003"},  
   {:position=>3, :id=>"GBMMV1800002"}  
]  
[in1, in2].map do |a|
  a.group_by { |h| h[:id] }
end.reduce do |h1, h2|
  h1.merge(h2) do |k, v1, v2|
    v2.first.merge(change: v1.first[:position] - v2.first[:position])
  end
end.values.sort_by { |h| h[:position] }
#⇒ [{:position=>1, :id=>"GBMMV1800001", :change=>0},
#   {:position=>2, :id=>"GBMMV1800003", :change=>1},
#   {:position=>3, :id=>"GBMMV1800002", :change=>-1}]

答案 1 :(得分:1)

chart1 = [
  {:position=>1, :id=>"GBMMV1800001"}, 
  {:position=>2, :id=>"GBMMV1800002"}, 
  {:position=>3, :id=>"GBMMV1800003"}
]

chart2 = [
  {:position=>1, :id=>"GBMMV1800001"}, 
  {:position=>2, :id=>"GBMMV1800003"},
  {:position=>3, :id=>"GBMMV1800002"}
]

h = chart1.each_with_index.with_object({}) { |(g,i),h| h[g[:id]] = i }
  #=> {"GBMMV1800001"=>0, "GBMMV1800002"=>1, "GBMMV1800003"=>2}
chart2.each_with_index.map { |g,i| g.merge(change: h[g[:id]] - i) }
  #=> [{:position=>1, :id=>"GBMMV1800001", :change=>0},
  #    {:position=>2, :id=>"GBMMV1800003", :change=>1},
  #    {:position=>3, :id=>"GBMMV1800002", :change=>-1}]

答案 2 :(得分:0)

鉴于

h1 = [
  {:position=>1, :id=>"GBMMV1800001"}, 
  {:position=>2, :id=>"GBMMV1800002"}, 
  {:position=>3, :id=>"GBMMV1800003"}
]

h2 = [
  {:position=>1, :id=>"GBMMV1800001"}, 
  {:position=>2, :id=>"GBMMV1800003"},
  {:position=>3, :id=>"GBMMV1800002"}
]

我想要一张{ id => [position1, position2] }的地图。

首先,我遍历h1以获得其位置

vals = {}
h1.each do |val|
  vals[val[:id]] = [val[:position]]
end

现在vals等于

{
  "GBMMV1800001" => [1],
  "GBMMV1800002" => [2],
  "GBMMV1800003" => [3]
}

然后我遍历第二个数组,添加其位置。

h2.each do |val|
  # This will ignore ids that aren't present in h1
  next unless vals[val[:id]]
  vals[val[:id]].push val[:position]
end

现在我拥有了计算差异所需的所有数据:

{
  "GBMMV1800001" => [1, 1],
  "GBMMV1800002" => [2, 3],
  "GBMMV1800003" => [3, 2]
}

要获得差异,我会使用transform_values与ruby 2.4或主动支持一起使用。顺便说一下,您也可以使用reduceeach_with_object

diffs = vals.transform_values { |(pos1, pos2)| pos2 - pos1 }

这会在块参数中使用destructuring

答案 3 :(得分:0)

这似乎可以解决问题

def get_position_changes array0, array1
  array1.map.with_index do |hash1, index|
    new_hash = hash1.dup
    new_hash[:change] = array0.index {|hash0| hash0[:id] == hash1[:id]} - index
    new_hash
  end
end

first_array = [
  {:position=>1, :id=>"GBMMV1800001"}, 
  {:position=>2, :id=>"GBMMV1800002"}, 
  {:position=>3, :id=>"GBMMV1800003"}
]

second_array = [
  {:position=>1, :id=>"GBMMV1800001"}, 
  {:position=>2, :id=>"GBMMV1800003"},
  {:position=>3, :id=>"GBMMV1800002"}
]

p get_position_changes(first_array, second_array)

#=> [
#=>   {:position=>1, :id=>"GBMMV1800001", :change=>0}
#=>   {:position=>2, :id=>"GBMMV1800003", :change=>1}
#=>   {:position=>3, :id=>"GBMMV1800002", :change=>-1}
#=> ]

答案 4 :(得分:0)

您开始使用的结构:

h1 = [
  {:position=>1, :id=>"GBMMV1800001"}, 
  {:position=>2, :id=>"GBMMV1800002"}, 
  {:position=>3, :id=>"GBMMV1800003"}
]
h2 = [
  {:position=>1, :id=>"GBMMV1800001"}, 
  {:position=>2, :id=>"GBMMV1800003"},
  {:position=>3, :id=>"GBMMV1800002"}
]

不合适。你应该开始使用以下结构:

a1 = h1.map{|h| h[:id]} # => ["GBMMV1800001", "GBMMV1800002", "GBMMV1800003"]
a2 = h2.map{|h| h[:id]} # => ["GBMMV1800001", "GBMMV1800003", "GBMMV1800002"]

如上所述,

b1 = a1.map.with_index(1).to_h
# => {"GBMMV1800001"=>1, "GBMMV1800002"=>2, "GBMMV1800003"=>3}
b2 = a2.map.with_index(1).to_h
# => {"GBMMV1800001"=>1, "GBMMV1800003"=>2, "GBMMV1800002"=>3}
b1.keys.map{|k| {id: k, position: b1[k], change: b2[k] - b1[k]}}
# => [
#      {:id=>"GBMMV1800001", :position=>1, :change=>0},
#      {:id=>"GBMMV1800002", :position=>2, :change=>1},
#      {:id=>"GBMMV1800003", :position=>3, :change=>-1}
#    ]