如何从哈希数组中获取特定属性?

时间:2017-03-20 21:14:52

标签: ruby-on-rails arrays ruby hash key-value

我有一个需要按imp排序的哈希数组,我希望从中获取特定属性。

array_of_hash is 
[
  {
      :id => "9",
      :subsystem => "xyz",
      :component => "xyz",
      :imp => "1",
      :old_serial => "55q",
      :current_serial => nil,
      :old_num => "same",
      :current_num => nil,
      :acceptable_nums => [
         "asdf",
         "qwer",
         "zxcv",
         "poiu"
    ]
},
 {
     :id => "10",
     :subsystem => "xyz",
     :component => "xyz",
     :imp => "4",
     :old_serial => "56t",
     :current_serial => nil,
     :old_num => "same",
     :current_num => nil,
     :acceptable_nums => [
         "asdf",
         "qwer",
         "zxcv",
         "poiu"
    ]
},
{
      :id => "11",
      :subsystem => "xyz",
      :component => "xyz",
      :imp => "3",
      :old_serial => "57s",
      :current_serial => nil,
      :old_num => "same",
      :current_num => nil,
      :acceptable_nums => [
        "asdf",
        "qwer",
        "zxcv",
        "poiu"
    ]
},
  {
     :id => "14",
     :subsystem => "xyz",
     :component => "xyz",
     :imp => "2",
     :old_serial => "58r",
     :current_serial => nil,
     :old_num => "same",
     :current_num => nil,
     :acceptable_nums => [
        "asdf",
        "qwer",
        "zxcv",
        "poiu"
    ]
}
]

第一步,排序

array_of_hash.sort_by {|hash| hash[:imp].to_i}

然后我想要特定的属性

期望输出有一些条件

{
      :imp => "1-4",  #It should be range
      :old_serial => "55q,56r,57s,58t",  #old_serial number should be separated with comma respectively 
      :old_num => "same",
      :acceptable_nums => [
         "asdf",
         "qwer",
         "zxcv",
         "poiu"
    ]
}

我无法弄清楚如何做到这一点。

3 个答案:

答案 0 :(得分:1)

您需要sort_bygroup_bymap的组合:

p array_of_hash.sort_by { |h| h[:imp] }
               .group_by{ |h| h.values_at(:acceptable_nums, :old_num) }
               .map{ |(old_num, nums), hashes|
  {
    imp: hashes.map{ |h| h[:imp].to_i },
    old_serial: hashes.map{ |h| h[:old_serial] }.join(','),
    old_num: old_num,
    acceptable_nums: nums
  }
}
# [{:imp=>[1, 2, 3, 4], :old_serial=>"55q,58r,57s,56t", :old_num=>["asdf", "qwer", "zxcv", "poiu"], :acceptable_nums=>"same"}]

输出是一个哈希数组。每个唯一的old_numacceptable_nums对都会有一个哈希值。在您的示例中,所有哈希都具有相同的对,因此只输出一个哈希值。

对于从[1,2,3,4]"1-4"的所需转换,slice_when的文档就是这样做的:

a = [1,2,4,9,10,11,12,15,16,19,20,21]
b = a.slice_when {|i, j| i+1 != j }
p b.to_a #=> [[1, 2], [4], [9, 10, 11, 12], [15, 16], [19, 20, 21]]
c = b.map {|a| a.length < 3 ? a : "#{a.first}-#{a.last}" }
p c #=> [[1, 2], [4], "9-12", [15, 16], "19-21"]
d = c.join(",")
p d #=> "1,2,4,9-12,15,16,19-21"

答案 1 :(得分:1)

imps, old_serials = array_of_hash.map { |h| [h[:imp], h[:old_serial]] }.
                                  sort_by(&:first).
                                  transpose
  #=> [["1", "2", "3", "4"], ["55q", "58r", "57s", "56t"]]

{ imp: "%d-%d" % imps.map(&:to_i).minmax, old_serial: old_serials.join(',') }.
  merge(array_of_hash.first.select { |k,_| [:old_num, :acceptable_nums].include?(k) })
  #=> {:imp=>"1-4", :old_serial=>"55q,58r,57s,56t", :old_num=>"same",
  #    :acceptable_nums=>["asdf", "qwer", "zxcv", "poiu"]} 

请注意

array_of_hash.first.select { |k,_| [:old_num, :acceptable_nums].include?(k) }
  # => {:old_num=>"same", :acceptable_nums=>["asdf", "qwer", "zxcv", "poiu"]}

答案 2 :(得分:0)

如果你逐步分解它,它会更容易阅读。

old_serial_numbers = array_of_hash.collect {|h| h[:old_serial]}.join(',')
reject_hash_keys = [:old_serial, :id, :subsystem, :component, :current_num, :current_serial]

clean_hash = array_of_hash.map do |hash| 
  hash.reject! {|k| reject_hash_keys.include? k }
  hash.merge(old_serial: old_serial_numbers)
end

clean_hash.sort_by {|hash| hash[:imp].to_i}