如何在Ruby on Rails上的哈希数组中删除重复的行

时间:2019-05-08 11:15:50

标签: arrays ruby hash

我在应用程序中使用的是Ruby 2.6。

我想删除哈希数组中的重复元素。这是我的输入

array_of_hashes = [
{"Date"=> "2019-05-6", "ID" => 100, "Rate" => 10, "Count" => 1},
{"Date"=> "2019-05-6", "ID" => 100, "Rate" => nil, "Count" => 0},
{"Date"=> "2019-05-6", "ID" => 101, "Rate" => 25, "Count" => 3},
{"Date"=> "2019-05-6", "ID" => 102, "Rate" => nil, "Count" => 0},
{"Date"=> "2019-05-6", "ID" => 102, "Rate" => 35, "Count" => 0},
{"Date"=> "2019-05-6", "ID" => 103, "Rate" => 20, "Count" => 6}
]

我正在为应用程序的需要从哈希中创建键,值对。

result = array_of_hashes.map { |row| [[row['ID'], row['Date'], row] }.to_h

如果在哈希中有两个记录具有相同的“ ID”和“ Date”值,我想在“ Rate”!= 0的行中排行,其中输入记录的顺序可能会乱序。这是我的实际和预期结果。

实际结果:

 {[100, "2019-05-6"]=>{"Date"=>"2019-05-6", "ID"=>100, "Rate"=>nil, "Count"=>0},
 [101, "2019-05-6"]=>{"Date"=>"2019-05-6", "ID"=>101, "Rate"=>25, "Count"=>3},
 [102, "2019-05-6"]=>{"Date"=>"2019-05-6", "ID"=>102, "Rate"=>35, "Count"=>0},
 [103, "2019-05-6"]=>{"Date"=>"2019-05-6", "ID"=>103, "Rate"=>20, "Count"=>6}}

预期结果:

 {[100, "2019-05-6"]=>{"Date"=>"2019-05-6", "ID"=>100, "Rate"=>10, "Count"=>1}, 
 [101, "2019-05-6"]=>{"Date"=>"2019-05-6", "ID"=>101, "Rate"=>25, "Count"=>3},
 [102, "2019-05-6"]=>{"Date"=>"2019-05-6", "ID"=>102, "Rate"=>35, "Count"=>0},
 [103, "2019-05-6"]=>{"Date"=>"2019-05-6", "ID"=>103, "Rate"=>20, "Count"=>6}}

如何获得上述预期结果?

3 个答案:

答案 0 :(得分:3)

这里是另一个按选项分组

array_of_hashes.group_by {|h| h.values_at("ID","Date")}.transform_values do |v|   
  v.find {|r| r["Rate"]}
end

#=> {[100, "2019-05-6"]=>{"Date"=>"2019-05-6", "ID"=>100, "Rate"=>10, "Count"=>1}, 
#    [101, "2019-05-6"]=>{"Date"=>"2019-05-6", "ID"=>101, "Rate"=>25, "Count"=>3}, 
#    [102, "2019-05-6"]=>{"Date"=>"2019-05-6", "ID"=>102, "Rate"=>35, "Count"=>0}, 
#    [103, "2019-05-6"]=>{"Date"=>"2019-05-6", "ID"=>103, "Rate"=>20, "Count"=>6}}

按ID和日期分组,然后将Hash值转换为第一个Hash,其中“费率”不是nil

如果可以接受多个值,则可以用find_allselect代替find

如果要保留原始结构,只需在末尾添加values

答案 1 :(得分:2)

我们可以通过一次通过array_of_hashes来构建所需的哈希。

array_of_hashes.each_with_object({}) do |g,h|
  k = [g['ID'], g['Date']]
  h.update(k=>g) unless h.key?(k) && h[k]['Rate'] != nil
end
  #=> {[100, "2019-05-6"]=>{"Date"=>"2019-05-6", "ID"=>100, "Rate"=>10, "Count"=>1},
  #    [101, "2019-05-6"]=>{"Date"=>"2019-05-6", "ID"=>101, "Rate"=>25, "Count"=>3},
  #    [102, "2019-05-6"]=>{"Date"=>"2019-05-6", "ID"=>102, "Rate"=>35, "Count"=>0},
  #    [103, "2019-05-6"]=>{"Date"=>"2019-05-6", "ID"=>103, "Rate"=>20, "Count"=>6}}

这假设如果array_of_hashes的两个元素在'ID''Date'的值上匹配,并且nil的值都不为'Rate',保留两个哈希中的第一个。如果应保留两者中的后者,则将方法的第二行更改为:

h.update(k=>g) unless h.key?(k) && g['Rate'].nil?

答案 2 :(得分:1)

使用group_by并从值中过滤零利率。

array_of_hashes
  .group_by { |h| [h["ID"], h["Date"]] }
  .map { |key, values| [key, values.reject { |row| row["Rate"].nil? }.last] }
  .to_h