【问题标题】:How to remove duplicate row in array of hashes on Ruby on rails如何在 Ruby on rails 中删除哈希数组中的重复行
【发布时间】:2019-05-08 11:15:50
【问题描述】:

我在我的应用程序中使用 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}}

我怎样才能得到上述预期的结果?

【问题讨论】:

  • 1. “预期结果”是否可以包含 Rate = nil 的值(哈希)? 2. array_of_hashes 是否可以包含两个元素,它们的 "ID""Date" 具有相同的值,而 "Rate" 都没有 nil 值?如果“是”,应该选择哪个?

标签: arrays ruby hash


【解决方案1】:

这是另一个按选项分组

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,其中“Rate”不是 nil

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

如果您想保持原始结构,只需在末尾添加 values

【讨论】:

  • ...或!r["Rate"].nil? 以便更好地阅读(?),而不必担心"Rate" 的值是false(尽管不太可能)。
  • @CarySwoveland 你真的认为这样更好吗?我更喜欢 v.lazy.reject {|r| r["Rate"].nil? }.first 而不是 find 第一个非 nil 率哈希返回而不考虑组中的其他哈希。
  • “读起来更好”,因为当我看到{|r| r["Rate"]} 的问题时,“false 怎么样?”立即想到并需要处理。我的"(?)" 反映了对! 的需求。我真正想要的是{|r| r["Rate"].non_nil? }
  • @CarySwoveland 你可以选择像r unless r['Rate'].nil?这样超级丑陋的东西
【解决方案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' 的值匹配,并且'Rate' 的值都不是nil,则保留两个散列中的第一个。如果应该保留两者中的后者,则将方法的第二行更改为:

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

【讨论】:

  • 对于您可以使用if h.dig(k,'Rate').nil? 的第一个解决方案,它很快就会失败,所以结果是一样的。
  • @engineersmnky,我以前没见过。聪明!
【解决方案3】:

使用 group_by 并从值中过滤 nil 率。

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

【讨论】:

  • 你不想要我假设的 rate 为 nil 的行吗?
  • 是的。我想要 rate 不是 nil 并且输入记录每次都打乱的行
  • 这里为什么需要.last?
  • 如果我们想要您指定的结果,则只返回一行。如果您希望每个 ID-Date 元组可能有几行,您只需删除 .last。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-07-27
  • 2010-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-09
相关资源
最近更新 更多